mirror of
https://github.com/frappe/books.git
synced 2026-08-24 02:24:17 -05:00
Merge pull request #1232 from suhailanzar/partial-Payment
fix: implement complete partial payment handling
This commit is contained in:
@@ -25,6 +25,7 @@ export class AccountingSettings extends Doc {
|
||||
enablePricingRule?: boolean;
|
||||
enableERPNextSync?: boolean;
|
||||
enablePointOfSaleWithOutInventory?: boolean;
|
||||
enablePartialPayment?: boolean;
|
||||
|
||||
static filters: FiltersMap = {
|
||||
writeOffAccount: () => ({
|
||||
|
||||
@@ -897,7 +897,9 @@ export abstract class Invoice extends Transactional {
|
||||
if (sinvreturnedDoc.outstandingAmount?.isZero()) {
|
||||
return this.grandTotal;
|
||||
} else {
|
||||
return this.fyo.pesa(0);
|
||||
return this.grandTotal
|
||||
?.abs()
|
||||
.sub(sinvreturnedDoc.outstandingAmount as Money);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ export class Payment extends Transactional {
|
||||
referenceType?: ModelNameEnum.SalesInvoice | ModelNameEnum.PurchaseInvoice;
|
||||
for?: PaymentFor[];
|
||||
_accountsMap?: AccountTypeMap;
|
||||
initialAmount?: Money;
|
||||
|
||||
async paymentMethodDoc() {
|
||||
return (await this.loadAndGetLink('paymentMethod')) as PaymentMethod;
|
||||
@@ -458,6 +459,22 @@ export class Payment extends Transactional {
|
||||
row.referenceName
|
||||
);
|
||||
|
||||
if (!this.fyo.singles.AccountingSettings?.enablePartialPayment) {
|
||||
const amount = !(this.amountPaid as Money).isZero()
|
||||
? (this.amountPaid as Money)
|
||||
: (this.amount as Money);
|
||||
const initialAmount = this.initialAmount as Money;
|
||||
if (amount.lt(initialAmount) && !amount.eq(initialAmount)) {
|
||||
if (this.writeoff?.isZero()) {
|
||||
row.amount = this.initialAmount;
|
||||
row.amountPaid = this.fyo.pesa(0);
|
||||
throw new ValidationError(
|
||||
this.fyo.t`Enable Partial payment to pay partial amount`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const previousOutstandingAmount = referenceDoc.outstandingAmount as Money;
|
||||
const outstandingAmount = previousOutstandingAmount.sub(row.amount!);
|
||||
await referenceDoc.setAndSync({ outstandingAmount });
|
||||
@@ -703,17 +720,22 @@ export class Payment extends Transactional {
|
||||
return;
|
||||
}
|
||||
|
||||
const amount = (this.getSum('for', 'amount', false) as Money).abs();
|
||||
|
||||
if ((value as Money).gt(amount)) {
|
||||
if (!this.initialAmount) {
|
||||
this.initialAmount = this.amount as Money;
|
||||
}
|
||||
if ((value as Money).gt(this.initialAmount)) {
|
||||
throw new ValidationError(
|
||||
this.fyo.t`Payment amount cannot
|
||||
exceed ${this.fyo.format(amount, 'Currency')}.`
|
||||
this.fyo.t`Payment amount cannot exceed ${this.fyo.format(
|
||||
this.initialAmount,
|
||||
'Currency'
|
||||
)}.`
|
||||
);
|
||||
} else if ((value as Money).isZero()) {
|
||||
throw new ValidationError(
|
||||
this.fyo.t`Payment amount cannot
|
||||
be ${this.fyo.format(value, 'Currency')}.`
|
||||
this.fyo.t`Payment amount cannot be ${this.fyo.format(
|
||||
value as Money,
|
||||
'Currency'
|
||||
)}.`
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -115,10 +115,12 @@ export class SalesInvoice extends Invoice {
|
||||
((value as number) || 0) *
|
||||
((loyaltyProgramDoc?.conversionFactor as number) || 0);
|
||||
|
||||
if (this.grandTotal?.lt(loyaltyPoint)) {
|
||||
throw new ValidationError(
|
||||
t`no need ${value as number} points to purchase this item`
|
||||
);
|
||||
if (!this.isReturn) {
|
||||
if (this.grandTotal?.lt(loyaltyPoint)) {
|
||||
throw new ValidationError(
|
||||
t`no need ${value as number} points to purchase this item`
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -149,6 +149,13 @@
|
||||
"default": false,
|
||||
"section": "Features"
|
||||
},
|
||||
{
|
||||
"fieldname": "enablePartialPayment",
|
||||
"label": "Enable Partial Payment",
|
||||
"fieldtype": "Check",
|
||||
"default": false,
|
||||
"section": "Features"
|
||||
},
|
||||
{
|
||||
"fieldname": "fiscalYearStart",
|
||||
"label": "Fiscal Year Start Date",
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
:show-label="true"
|
||||
:border="true"
|
||||
:value="row.itemDiscountAmount"
|
||||
:read-only="isDiscountsReadOnly(row.itemDiscountPercent as number < 0)"
|
||||
:read-only="isDiscountsReadOnly(row.itemDiscountPercent as number > 0)"
|
||||
@change="(value:number) => setItemDiscount('amount', value)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -530,7 +530,7 @@ export default defineComponent({
|
||||
this.tableView = !this.tableView;
|
||||
},
|
||||
setPaidAmount(amount: Money) {
|
||||
this.paidAmount = amount;
|
||||
this.paidAmount = this.fyo.pesa(amount.toString());
|
||||
},
|
||||
setPaymentMethod(method: string) {
|
||||
this.paymentMethod = method;
|
||||
@@ -825,6 +825,7 @@ export default defineComponent({
|
||||
const paymentMethod = this.paymentMethod;
|
||||
|
||||
await this.paymentDoc.set('paymentMethod', paymentMethod);
|
||||
await this.paymentDoc.set('amount', this.fyo.pesa(this.paidAmount.float));
|
||||
|
||||
const paymentMethodDoc = await this.paymentDoc.loadAndGetLink(
|
||||
'paymentMethod'
|
||||
@@ -832,7 +833,6 @@ export default defineComponent({
|
||||
|
||||
if (paymentMethodDoc?.type !== 'Cash') {
|
||||
await this.paymentDoc.setMultiple({
|
||||
amount: this.paidAmount.float,
|
||||
referenceId: this.transferRefNo,
|
||||
clearanceDate: this.transferClearanceDate,
|
||||
});
|
||||
@@ -841,7 +841,6 @@ export default defineComponent({
|
||||
if (paymentMethodDoc?.type === 'Cash') {
|
||||
await this.paymentDoc.setMultiple({
|
||||
paymentAccount: this.defaultPOSCashAccount,
|
||||
amount: this.paidAmount.float,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
:border="true"
|
||||
:text-right="true"
|
||||
:value="paidAmount"
|
||||
@change="(amount:Money)=> $emit('setPaidAmount', amount)"
|
||||
@change="(amount:Money)=> $emit('setPaidAmount', (amount as Money).float)"
|
||||
/>
|
||||
<div class="grid grid-cols-2 gap-6">
|
||||
<Button
|
||||
@@ -128,6 +128,15 @@
|
||||
:text-right="true"
|
||||
:value="sinvDoc?.grandTotal"
|
||||
/>
|
||||
|
||||
<Currency
|
||||
:df="sinvDoc.fieldMap.outstandingAmount"
|
||||
:read-only="true"
|
||||
:show-label="true"
|
||||
:border="true"
|
||||
:text-right="true"
|
||||
:value="sinvDoc?.outstandingAmount"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 bottom-8">
|
||||
@@ -278,10 +287,7 @@ export default defineComponent({
|
||||
return this.fyo.pesa(this.paidAmount.float).sub(grandTotal);
|
||||
},
|
||||
showBalanceAmount(): boolean {
|
||||
if (
|
||||
this.fyo.pesa(this.paidAmount.float).eq(fyo.pesa(0)) &&
|
||||
this.transferAmount.eq(fyo.pesa(0))
|
||||
) {
|
||||
if (this.paidAmount.float === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -368,7 +374,10 @@ export default defineComponent({
|
||||
setPaymentMethodAndAmount(paymentMethod?: string) {
|
||||
if (paymentMethod) {
|
||||
this.$emit('setPaymentMethod', paymentMethod);
|
||||
this.$emit('setPaidAmount', (this.sinvDoc.grandTotal as Money).float);
|
||||
this.$emit(
|
||||
'setPaidAmount',
|
||||
(this.sinvDoc.outstandingAmount as Money).float
|
||||
);
|
||||
}
|
||||
},
|
||||
async setPaymentMethods() {
|
||||
|
||||
Reference in New Issue
Block a user