Heartinz Essentials

heartinz_essentials is Heartinz's shared money-math and date/time toolkit for our Flutter/Dart apps (used today in the Negobill POS app). All monetary amounts are integers in subunits (paise/cents) to avoid floating-point rounding bugs, and every calculation uses package:decimal internally with banker's rounding for consistent, predictable results.

Everything is exposed through a single entry point:

final essentials = Essentials();

...with calculators grouped into sub-modules: calc, currency, date, unit, purchase, offer, and returnPrice.

Why this package exists

Sale, purchase, stock, and return screens across the app all need the same GST/MRP/tax breakdown math, the same unit conversions (e.g. Kg ↔ Gram), and the same ISO date-time handling. Instead of re-implementing (and re-debugging rounding edge cases) in every feature, that logic lives here once, is unit-tested, and is versioned independently.

Features / Modules

essentials.calc — Grand total & GST

  • calculateGrandTotal(...) — rolls up MRP, sale price, base price, and tax amount into a GrandTotalModel (grand total, SGST/CGST/IGST split, amount in words).
  • gstCalculate(...) — full price breakdown for a single line item (MRP, discount, sale price, base price, tax %, SGST/CGST/IGST, line totals) as a GSTResult.
  • findGstAmountSplit(taxAmount) — splits a tax amount into SGST/CGST halves.

essentials.currency — Currency conversion

  • toCurrency(amountInSubunits, currencyCode) — subunits → display currency (e.g. 15000 paise → ₹150.00). Supports INR, USD, GBP, EUR, JPY.
  • toSubunit(amount, currencyCode) — display currency → subunits, for storing/ computing without floats.

essentials.date — ISO date/time utilities

  • displayIso(isoString) — ISO string → map of common display formats (dd MMM yyyy, dd/MM/yyyy, etc).
  • toTimeZone(isoTime, targetTimeZone) — convert an ISO time into another IANA timezone (e.g. Asia/Kolkata).
  • getCurrentTimeByTimeZone(timeZone) — current time in a given timezone, in multiple display formats.
  • dayBoundariesInUTC(isoDateStr) — start/end of the local day, expressed in UTC (handy for "today's sales" style date-range queries).
  • timeDifference(isoA, isoB) — difference between two ISO timestamps.
  • modifyIso(isoTime, duration) — add/subtract a Duration from an ISO time.
  • splitIso(isoString) — break an ISO string into its date/time components.
  • toIso({dateStr, type, timeZone}) — parse a formatted date string into ISO 8601.
  • toUtc(isoTime) — convert an ISO time to UTC.

essentials.unit — Unit conversion (primary ↔ secondary)

For products sold in two units (e.g. Kg as primary, Gram as secondary):

  • toPrimaryQuantity(secondaryQty, {unitConfig}) / toSecondaryQuantity(primaryQty, {unitConfig}) — convert quantities between units using a UnitConfig (unit names/codes + conversion ratio).
  • toPrimaryUnitPrice(...) / toSecondaryUnitPrice(...) — convert a full MRP/sale/ base price breakdown from one unit to the other, returning a GSTResult for the target unit.

essentials.purchase — Purchase price breakdown

  • getPurchaseAmount(...) — given catalog prices (MRP/sale/base per unit), quantity, and either a tax-inclusive or tax-exclusive total purchase amount, returns both the resulting sale-side breakdown (SaleAmountList) and purchase-side breakdown (PurchaseAmountList) as a PurchaseAmountResult.
  • getPurchaseGrandTotal(...) — rolls up total purchase MRP/price/tax across line items into a PurchaseGrandTotalResult (with amount-in-words).

essentials.offer — Discounts

  • getOfferAmount(amount, offerPercent) — final price after applying an offer/discount percent to an amount (subunits).
  • getOfferPercent(mrp, salePrice) — discount percent represented by selling at salePrice against mrp.

essentials.returnPrice — Sales returns

  • getReturnAmountList(...) — price breakdown for a single return line item (MRP, sold price, returned/cancelled price, tax split).
  • getReturnGrandTotal(...) — rolls up total return amounts (returned + cancelled) into a ReturnGrandTotalResult, with amount-in-words for both the raw and rounded totals.

Getting started

Add the package to your pubspec.yaml:

dependencies:
  heartinz_essentials: ^3.3.0

Then fetch it:

flutter pub get

Usage

import 'package:decimal/decimal.dart';
import 'package:heartinz_essentials/heartinz_essentials.dart';

final essentials = Essentials();

// GST / line-item price breakdown
final gst = essentials.calc.gstCalculate(
  mrp: essentials.currency.toSubunit(200, "INR"),
  salePrice: essentials.currency.toSubunit(150, "INR"),
  basePrice: 0,
  taxPercent: 18,
  quantity: 2,
  lock: "SALEPRICE", // which field (MRP/SALEPRICE/BASEPRICE) drives the calc
);
print(gst.toJson());

// Offer / discount
final finalPrice = essentials.offer.getOfferAmount(gst.mrp, 15); // 15% off
final discountPercent = essentials.offer.getOfferPercent(gst.mrp, gst.salePrice);

// Unit conversion, e.g. Kg (primary) <-> Gram (secondary)
final unitConfig = UnitConfig(
  primaryUnitCode: 'kg',
  primaryUnitName: 'Kilogram',
  secondaryUnitCode: 'g',
  secondaryUnitName: 'Gram',
  conversion: Decimal.parse('1000'),
);
final inGrams = essentials.unit.toSecondaryQuantity(
  Decimal.parse('1.5'), // 1.5 kg
  unitConfig: unitConfig,
);
print(inGrams.secondaryQty); // 1500

// Current time in a store's timezone
final storeTime = essentials.date.getCurrentTimeByTimeZone("Asia/Kolkata");
print(storeTime['shortMonthFormat']);

See example/example.dart for more runnable snippets covering grand totals, currency conversion, and date/time helpers, and the example/test/ directory for expected input/output pairs for every module.

Notes

  • All monetary parameters are integers in subunits (e.g. paise for INR), not floating-point currency values — convert with essentials.currency.toSubunit(...) first if you're starting from a display value like 150.50.
  • Rounding uses banker's rounding (round-half-to-even) throughout for consistency with backend calculations (this package mirrors the rounding/precision rules of the @heartinz/finance JS package, so results match across platforms).
  • lock parameters (e.g. "MRP", "SALEPRICE", "BASEPRICE") tell a calculator which of the given prices is authoritative when the others need to be derived/ recomputed.