2
0
mirror of https://github.com/frappe/books.git synced 2024-11-14 01:14:03 +00:00
books/models/baseModels/tests/testInvoice.spec.ts
2023-09-23 16:46:40 +05:30

283 lines
6.7 KiB
TypeScript

import test from 'tape';
import { closeTestFyo, getTestFyo, setupTestFyo } from 'tests/helpers';
import { ModelNameEnum } from 'models/types';
import { SalesInvoice } from '../SalesInvoice/SalesInvoice';
import { Payment } from '../Payment/Payment';
import { PaymentTypeEnum } from '../Payment/types';
import {
assertDoesNotThrow,
assertThrows,
} from 'backend/database/tests/helpers';
import { PurchaseInvoice } from '../PurchaseInvoice/PurchaseInvoice';
const fyo = getTestFyo();
setupTestFyo(fyo, __filename);
const itemData = {
name: 'Pen',
rate: 100,
unit: 'Unit',
for: 'Both',
trackItem: true,
hasBatch: true,
hasSerialNumber: true,
};
const partyData = {
name: 'John Whoe',
email: 'john@whoe.com',
};
const batchMap = {
batchOne: {
name: 'PN-AB001',
manufactureDate: '2022-11-03T09:57:04.528',
},
batchTwo: {
name: 'PN-AB002',
manufactureDate: '2022-10-03T09:57:04.528',
},
};
test('create test docs', async (t) => {
await fyo.doc.getNewDoc(ModelNameEnum.Item, itemData).sync();
t.ok(
fyo.db.exists(ModelNameEnum.Item, itemData.name),
`dummy item ${itemData.name} exists`
);
await fyo.doc.getNewDoc(ModelNameEnum.Party, partyData).sync();
t.ok(
fyo.db.exists(ModelNameEnum.Party, partyData.name),
`dummy party ${partyData.name} exists`
);
for (const batch of Object.values(batchMap)) {
await fyo.doc.getNewDoc(ModelNameEnum.Batch, batch).sync(),
t.ok(
fyo.db.exists(ModelNameEnum.Batch, batch.name),
`batch ${batch.name} exists`
);
}
});
test('create SINV with batch then create payment against it', async (t) => {
const sinvDoc = fyo.doc.getNewDoc(ModelNameEnum.SalesInvoice, {
account: 'Debtors',
party: partyData.name,
items: [
{
item: itemData.name,
batch: batchMap.batchOne.name,
rate: itemData.rate,
quantity: 2,
},
],
}) as SalesInvoice;
await sinvDoc.sync();
await sinvDoc.runFormulas();
await sinvDoc.submit();
t.ok(
fyo.db.exists(ModelNameEnum.SalesInvoice, sinvDoc.name),
`${sinvDoc.name} exists`
);
const paymentDoc = sinvDoc.getPayment();
await paymentDoc?.sync();
await paymentDoc?.submit();
t.equals(paymentDoc?.name, 'PAY-1001');
});
test('create SINV return for one qty', async (t) => {
const sinvDoc = (await fyo.doc.getDoc(
ModelNameEnum.SalesInvoice,
'SINV-1001'
)) as SalesInvoice;
let returnDoc = (await sinvDoc?.getReturnDoc()) as SalesInvoice;
returnDoc.items = [];
returnDoc.append('items', {
item: itemData.name,
batch: batchMap.batchOne.name,
quantity: 1,
rate: itemData.rate,
});
await returnDoc.runFormulas();
await returnDoc.sync();
await returnDoc.submit();
t.ok(
await fyo.db.exists(ModelNameEnum.SalesInvoice, returnDoc.name),
'SINV return for one qty created'
);
t.equals(
returnDoc.outstandingAmount?.float,
itemData.rate,
'returnDoc outstanding amount matches'
);
const returnSinvAles = await fyo.db.getAllRaw(
ModelNameEnum.AccountingLedgerEntry,
{
fields: ['name', 'account', 'credit', 'debit'],
filters: { referenceName: returnDoc.name! },
}
);
for (const ale of returnSinvAles) {
if (ale.account === 'Sales') {
t.equal(
fyo.pesa(ale.debit as string).float,
fyo.pesa(itemData.rate).float,
`return Invoice debited from ${ale.account}`
);
}
if (ale.account === 'Debtors') {
t.equal(
fyo.pesa(ale.credit as string).float,
fyo.pesa(itemData.rate).float,
`return Invoice credited to ${ale.account}`
);
}
}
await assertThrows(
async () => await sinvDoc.cancel(),
'can not cancel a SINV when a return invoice is created against it'
);
});
test('create SINV return for balance qty', async (t) => {
const sinvDoc = (await fyo.doc.getDoc(
ModelNameEnum.SalesInvoice,
'SINV-1001'
)) as SalesInvoice;
const returnDoc = (await sinvDoc?.getReturnDoc()) as SalesInvoice;
t.equals(
Object.values(returnDoc.items!)[0].quantity,
-1,
'return doc has 1 qty left to return'
);
await returnDoc.sync();
await returnDoc.runFormulas();
await returnDoc.submit();
t.ok(
await fyo.db.exists(ModelNameEnum.SalesInvoice, returnDoc.name),
'SINV return for one qty created'
);
t.equals(
returnDoc.outstandingAmount?.float,
-itemData.rate,
'return doc outstanding amount matches'
);
});
test('create payment for return invoice', async (t) => {
const returnDoc = (await fyo.doc.getDoc(
ModelNameEnum.SalesInvoice,
'SINV-1002'
)) as SalesInvoice;
t.equals(returnDoc.returnAgainst, 'SINV-1001');
const paymentDoc = returnDoc.getPayment() as Payment;
t.equals(paymentDoc.paymentType, PaymentTypeEnum.Pay, 'payment type is pay');
t.equals(
paymentDoc.amount?.float,
itemData.rate,
'payment amount for return invoice matches'
);
await paymentDoc.sync();
t.ok(
await fyo.db.exists(ModelNameEnum.Payment, paymentDoc.name),
'payment entry created for return invoice'
);
await assertDoesNotThrow(
async () => await returnDoc.cancel(),
'return invoice cancelled'
);
});
test('creating PINV return when invoice is not paid', async (t) => {
const pinvDoc = fyo.doc.getNewDoc(
ModelNameEnum.PurchaseInvoice
) as PurchaseInvoice;
await pinvDoc.set({
party: partyData.name,
account: 'Creditors',
items: [
{
item: itemData.name,
batch: batchMap.batchOne.name,
quantity: 2,
rate: itemData.rate,
},
],
});
await pinvDoc.sync();
await pinvDoc.submit();
t.equals(pinvDoc.name, 'PINV-1001', `${pinvDoc.name} is submitted`);
const returnDoc = (await pinvDoc.getReturnDoc()) as PurchaseInvoice;
await returnDoc.sync();
await returnDoc.submit();
t.equals(
returnDoc?.returnAgainst,
pinvDoc.name,
`return pinv created against ${pinvDoc.name}`
);
t.equals(
Object.values(returnDoc.items!)[0].quantity,
-2,
'pinv returned qty matches'
);
const returnSinvAles = await fyo.db.getAllRaw(
ModelNameEnum.AccountingLedgerEntry,
{
fields: ['name', 'account', 'credit', 'debit'],
filters: { referenceName: returnDoc.name! },
}
);
for (const ale of returnSinvAles) {
if (ale.account === 'Creditors') {
t.equal(
fyo.pesa(ale.debit as string).float,
returnDoc.outstandingAmount!.float,
`return Invoice debited from ${ale.account}`
);
}
if (ale.account === 'Cost of Goods Sold') {
t.equal(
fyo.pesa(ale.credit as string).float,
returnDoc.outstandingAmount!.float,
`return Invoice credited to ${ale.account}`
);
}
}
});
closeTestFyo(fyo, __filename);