@zenuinebit/sales-return
v0.1.0
Published
Sales returns and credit notes: quantity limits, prorated discounts, exact tax reversal, refund splits, restock movements.
Readme
@zenuinebit/sales-return
Sales returns that produce a GST credit note: quantity limits, prorated discounts, a refund amount, refund split across payment methods, and stock coming back. Builds on @zenuinebit/gst-report, @zenuinebit/money and @zenuinebit/stock-ledger. Amounts are integers in minor units; dates are "YYYY-MM-DD".
import { createReturn, returnable, splitRefund, toStockMovements } from "@zenuinebit/sales-return";
import { generateReport } from "@zenuinebit/gst-report";
const sale = {
number: "INV-1", date: "2025-04-10", placeOfSupply: "Maharashtra",
lines: [{ sku: "TEA", description: "Tea", hsn: "0902", quantity: 10, unitPrice: 10_000, discount: 1_000, taxRate: 5 }],
};
const ret = createReturn(
sale,
{ number: "CN-1", date: "2025-04-15", items: [{ sku: "TEA", quantity: 4 }], reason: "Stale" },
{ supplier: "27AAPFU0939F1ZV", maxDays: 30, previous: [] }, // pass earlier returns of this sale as `previous`
);
ret.refund; // 41_580 - what to give back, positive
ret.creditNote; // a gst-report invoice (type "credit-note"): include it in generateReport / e-invoice / e-way flows
returnable(sale, [ret]); // { TEA: 6 } still returnable
splitRefund(ret.refund, [{ method: "cash", amount: 20_000 }, { method: "card", amount: 80_000 }]);
// refund shared in proportion to what each method paid; the parts add up exactly
toStockMovements(ret, { TEA: 6_000 }); // goods back in stock at a unit cost, for stock-ledgerRules it enforces
- Returning more than was sold, counting earlier returns, is refused. So is a return dated before the sale, or after
maxDays. - The line discount comes back in proportion to the units returned; the return that finishes a line takes whatever discount is left, so the discount reverses exactly (333 + 333 + 334 on a 1,000 discount over three returns of one unit each).
- Tax is worked out like a sale, per line. A line returned in several pieces can differ from the original tax by a minor unit because of rounding; the taxable value reverses exactly (for whole quantities).
- Works for tax-inclusive sales too.
restock: false(damaged goods) leaves a line out of the stock movements. Restocking needs a unit cost for each line, because stock needs a value.
Not included: storing returns, exchanges (a return plus a new sale), refunds to a different method than the original payment, restocking fees, and e-invoice or e-way handling of the credit note (see @zenuinebit/einvoice-irn).
