Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: payment methods #1071

Merged
merged 6 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 1 addition & 4 deletions backend/database/bespoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -402,10 +402,7 @@ export class BespokeQueries {
const sinvNamesQuery = db.knex!(ModelNameEnum.SalesInvoice)
.select('name')
.where('isPOS', true)
.andWhereBetween('date', [
DateTime.fromJSDate(fromDate).toSQLDate(),
DateTime.fromJSDate(toDate).toSQLDate(),
]);
.andWhereBetween('date', [fromDate.toISOString(), toDate.toISOString()]);

if (lastShiftClosingDate) {
sinvNamesQuery.andWhere(
Expand Down
57 changes: 57 additions & 0 deletions backend/patches/createPaymentMethods.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { ModelNameEnum } from 'models/types';
import { DatabaseManager } from '../database/manager';
import { AccountTypeEnum } from 'models/baseModels/Account/types';
import { getDefaultMetaFieldValueMap } from 'backend/helpers';

type AccountTypeMap = Record<AccountTypeEnum, string[] | undefined>;

async function execute(dm: DatabaseManager) {
const accounts = (await dm.db?.getAll(ModelNameEnum.Account, {
fields: ['name', 'accountType'],
filters: {
accountType: [
'in',
[
AccountTypeEnum.Bank,
AccountTypeEnum.Cash,
AccountTypeEnum.Payable,
AccountTypeEnum.Receivable,
],
],
},
})) as { name: string; accountType: AccountTypeEnum }[];

const accountsMap = accounts.reduce((acc, ac) => {
acc[ac.accountType] ??= [];
acc[ac.accountType]!.push(ac.name);
return acc;
}, {} as AccountTypeMap);

const defaults = getDefaultMetaFieldValueMap();

const paymentMethods = [
{
name: 'Cash',
type: 'Cash',
account: accountsMap[AccountTypeEnum.Cash]?.[0],
...defaults,
},
{
name: 'Bank',
type: 'Bank',
account: accountsMap[AccountTypeEnum.Bank]?.[0],
...defaults,
},
{
name: 'Transfer',
type: 'Bank',
account: accountsMap[AccountTypeEnum.Bank]?.[0],
...defaults,
},
];

for (const paymentMethod of paymentMethods) {
await dm.db?.insert(ModelNameEnum.PaymentMethod, paymentMethod);
}
}
export default { execute };
6 changes: 6 additions & 0 deletions backend/patches/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import updateSchemas from './updateSchemas';
import setPaymentReferenceType from './setPaymentReferenceType';
import fixLedgerDateTime from './v0_21_0/fixLedgerDateTime';
import fixItemHSNField from './fixItemHSNField';
import createPaymentMethods from './createPaymentMethods';

export default [
{ name: 'testPatch', version: '0.5.0-beta.0', patch: testPatch },
Expand Down Expand Up @@ -42,4 +43,9 @@ export default [
patch: fixLedgerDateTime,
},
{ name: 'fixItemHSNField', version: '0.24.0', patch: fixItemHSNField },
{
name: 'createPaymentMethods',
version: '0.25.1',
patch: createPaymentMethods,
},
] as Patch[];
59 changes: 37 additions & 22 deletions models/baseModels/Payment/Payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import {
FormulaMap,
HiddenMap,
ListViewSettings,
RequiredMap,
ValidationMap,
} from 'fyo/model/types';
import { NotFoundError, ValidationError } from 'fyo/utils/errors';
Expand All @@ -27,8 +26,9 @@ import { AccountTypeEnum } from '../Account/types';
import { Invoice } from '../Invoice/Invoice';
import { Party } from '../Party/Party';
import { PaymentFor } from '../PaymentFor/PaymentFor';
import { PaymentMethod, PaymentType } from './types';
import { PaymentType } from './types';
import { TaxSummary } from '../TaxSummary/TaxSummary';
import { PaymentMethod } from '../PaymentMethod/PaymentMethod';

type AccountTypeMap = Record<AccountTypeEnum, string[] | undefined>;

Expand All @@ -38,10 +38,15 @@ export class Payment extends Transactional {
amount?: Money;
writeoff?: Money;
paymentType?: PaymentType;
paymentMethod?: string;
referenceType?: ModelNameEnum.SalesInvoice | ModelNameEnum.PurchaseInvoice;
for?: PaymentFor[];
_accountsMap?: AccountTypeMap;

async paymentMethodDoc() {
return (await this.loadAndGetLink('paymentMethod')) as PaymentMethod;
}

async change({ changed }: ChangeArg) {
if (changed === 'for') {
this.updateAmountOnReferenceUpdate();
Expand Down Expand Up @@ -110,6 +115,7 @@ export class Payment extends Transactional {
this.validateAccounts();
this.validateTotalReferenceAmount();
await this.validateReferences();
await this.validateReferencesAreSet();
}

async validateFor() {
Expand Down Expand Up @@ -223,6 +229,22 @@ export class Payment extends Transactional {
);
}

async validateReferencesAreSet() {
const type = (await this.paymentMethodDoc()).type;

if (type !== 'Bank') {
return;
}

if (!this.clearanceDate) {
throw new ValidationError(t`Clearance Date not set.`);
}

if (!this.referenceId) {
throw new ValidationError(t`Reference Id not set.`);
}
}

async getTaxSummary() {
const taxes: Record<
string,
Expand Down Expand Up @@ -559,15 +581,13 @@ export class Payment extends Transactional {
);
}

if (this.paymentMethod === 'Cash') {
return accountsMap[AccountTypeEnum.Cash]?.[0] ?? null;
}
const paymentMethodDoc = await this.paymentMethodDoc();

if (this.paymentMethod !== 'Cash') {
return accountsMap[AccountTypeEnum.Bank]?.[0] ?? null;
if (paymentMethodDoc.type === 'Cash') {
return accountsMap[AccountTypeEnum.Cash]?.[0] ?? null;
}

return null;
return accountsMap[AccountTypeEnum.Bank]?.[0] ?? null;
},
dependsOn: ['paymentMethod', 'paymentType', 'party'],
},
Expand All @@ -582,15 +602,17 @@ export class Payment extends Transactional {
);
}

if (this.paymentMethod === 'Cash') {
return accountsMap[AccountTypeEnum.Cash]?.[0] ?? null;
const paymentMethodDoc = await this.paymentMethodDoc();

if (paymentMethodDoc.account) {
return paymentMethodDoc.get('account');
}

if (this.paymentMethod !== 'Cash') {
return accountsMap[AccountTypeEnum.Bank]?.[0] ?? null;
if (paymentMethodDoc.type === 'Cash') {
return accountsMap[AccountTypeEnum.Cash]?.[0] ?? null;
}

return null;
return accountsMap[AccountTypeEnum.Bank]?.[0] ?? null;
},
dependsOn: ['paymentMethod', 'paymentType', 'party'],
},
Expand Down Expand Up @@ -673,14 +695,7 @@ export class Payment extends Transactional {
},
};

required: RequiredMap = {
referenceId: () => this.paymentMethod !== 'Cash',
clearanceDate: () => this.paymentMethod !== 'Cash',
};

hidden: HiddenMap = {
referenceId: () => this.paymentMethod === 'Cash',
clearanceDate: () => this.paymentMethod === 'Cash',
amountPaid: () => this.writeoff?.isZero() ?? true,
attachment: () =>
!(this.attachment || !(this.isSubmitted || this.isCancelled)),
Expand Down Expand Up @@ -712,7 +727,7 @@ export class Payment extends Transactional {
return { accountType: 'Receivable', isGroup: false };
}

if (paymentMethod === 'Cash') {
if (paymentMethod.name === 'Cash') {
return { accountType: 'Cash', isGroup: false };
} else {
return { accountType: ['in', ['Bank', 'Cash']], isGroup: false };
Expand All @@ -726,7 +741,7 @@ export class Payment extends Transactional {
return { accountType: 'Payable', isGroup: false };
}

if (paymentMethod === 'Cash') {
if (paymentMethod.name === 'Cash') {
return { accountType: 'Cash', isGroup: false };
} else {
return { accountType: ['in', ['Bank', 'Cash']], isGroup: false };
Expand Down
16 changes: 16 additions & 0 deletions models/baseModels/PaymentMethod/PaymentMethod.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Doc } from 'fyo/model/doc';
import { Account } from '../Account/Account';
import { ListViewSettings } from 'fyo/model/types';
import { PaymentMethodType } from 'models/types';

export class PaymentMethod extends Doc {
name?: string;
account?: Account;
type?: PaymentMethodType;

static getListViewSettings(): ListViewSettings {
return {
columns: ['name', 'type'],
};
}
}
2 changes: 2 additions & 0 deletions models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { Lead } from './baseModels/Lead/Lead';
import { AppliedCouponCodes } from './baseModels/AppliedCouponCodes/AppliedCouponCodes';
import { CouponCode } from './baseModels/CouponCode/CouponCode';
import { Payment } from './baseModels/Payment/Payment';
import { PaymentMethod } from './baseModels/PaymentMethod/PaymentMethod';
import { PaymentFor } from './baseModels/PaymentFor/PaymentFor';
import { PriceList } from './baseModels/PriceList/PriceList';
import { PriceListItem } from './baseModels/PriceList/PriceListItem';
Expand Down Expand Up @@ -69,6 +70,7 @@ export const models = {
CollectionRulesItems,
CouponCode,
Payment,
PaymentMethod,
PaymentFor,
PrintSettings,
PriceList,
Expand Down
3 changes: 3 additions & 0 deletions models/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export enum ModelNameEnum {

AppliedCouponCodes = 'AppliedCouponCodes',
Payment = 'Payment',
PaymentMethod = 'PaymentMethod',
PaymentFor = 'PaymentFor',
PriceList = 'PriceList',
PricingRule = 'PricingRule',
Expand Down Expand Up @@ -68,3 +69,5 @@ export enum ModelNameEnum {
}

export type ModelName = keyof typeof ModelNameEnum;

export type PaymentMethodType= 'Cash' | 'Bank'
18 changes: 3 additions & 15 deletions schemas/app/Payment.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,11 @@
"fieldname": "paymentMethod",
"label": "Payment Method",
"placeholder": "Payment Method",
"fieldtype": "Select",
"options": [
{
"value": "Cash",
"label": "Cash"
},
{
"value": "Cheque",
"label": "Cheque"
},
{
"value": "Transfer",
"label": "Transfer"
}
],
"fieldtype": "Link",
"target": "PaymentMethod",
"default": "Cash",
"required": true,
"create": true,
"section": "Details"
},
{
Expand Down
35 changes: 35 additions & 0 deletions schemas/app/PaymentMethod.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "PaymentMethod",
"label": "Payment Method",
"naming": "manual",
"fields": [
{
"fieldname": "name",
"label": "Name",
"fieldtype": "Data"
},
{
"fieldname": "type",
"label": "Type",
"fieldtype": "Select",
"required": true,
"options": [
{
"value": "Cash",
"label": "Cash"
},
{
"value": "Bank",
"label": "Bank"
}
]
},
{
"fieldname": "account",
"label": "Account",
"fieldtype": "Link",
"target": "Account"
}
],
"quickEditFields": ["name", "type", "account"]
}
2 changes: 2 additions & 0 deletions schemas/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import CollectionRulesItems from './app/CollectionRulesItems.json';
import CouponCode from './app/CouponCode.json';
import AppliedCouponCodes from './app/AppliedCouponCodes.json';
import Payment from './app/Payment.json';
import PaymentMethod from './app/PaymentMethod.json';
import PaymentFor from './app/PaymentFor.json';
import PriceList from './app/PriceList.json';
import PriceListItem from './app/PriceListItem.json';
Expand Down Expand Up @@ -117,6 +118,7 @@ export const appSchemas: Schema[] | SchemaStub[] = [
CollectionRulesItems as Schema,

Payment as Schema,
PaymentMethod as Schema,
PaymentFor as Schema,

JournalEntry as Schema,
Expand Down
3 changes: 2 additions & 1 deletion src/components/POS/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ export type PosEmits =
| 'addItem'
| 'toggleView'
| 'toggleModal'
| 'setCashAmount'
| 'setPaidAmount'
| 'setPaymentMethod'
| 'setCouponsCount'
| 'routeToSinvList'
| 'applyPricingRule'
Expand Down
Loading