2022-04-28 12:37:07 +00:00
|
|
|
import { Fyo, t } from 'fyo';
|
2022-04-24 06:48:44 +00:00
|
|
|
import { Doc } from 'fyo/model/doc';
|
2024-08-09 05:11:54 +00:00
|
|
|
import {
|
|
|
|
Action,
|
|
|
|
ColumnConfig,
|
|
|
|
DocStatus,
|
|
|
|
LeadStatus,
|
|
|
|
RenderData,
|
|
|
|
} from 'fyo/model/types';
|
2022-04-19 06:05:39 +00:00
|
|
|
import { DateTime } from 'luxon';
|
2022-05-23 05:30:54 +00:00
|
|
|
import { Money } from 'pesa';
|
2022-11-07 07:15:38 +00:00
|
|
|
import { safeParseFloat } from 'utils/index';
|
2022-04-14 05:24:11 +00:00
|
|
|
import { Router } from 'vue-router';
|
2022-05-14 08:46:05 +00:00
|
|
|
import {
|
|
|
|
AccountRootType,
|
2022-11-21 06:35:05 +00:00
|
|
|
AccountRootTypeEnum,
|
2022-05-14 08:46:05 +00:00
|
|
|
} from './baseModels/Account/types';
|
2023-06-22 08:52:54 +00:00
|
|
|
import { numberSeriesDefaultsMap } from './baseModels/Defaults/Defaults';
|
2022-11-22 09:12:49 +00:00
|
|
|
import { Invoice } from './baseModels/Invoice/Invoice';
|
2023-12-22 08:50:35 +00:00
|
|
|
import { SalesQuote } from './baseModels/SalesQuote/SalesQuote';
|
2023-01-16 09:38:02 +00:00
|
|
|
import { StockMovement } from './inventory/StockMovement';
|
|
|
|
import { StockTransfer } from './inventory/StockTransfer';
|
2023-05-04 10:45:12 +00:00
|
|
|
import { InvoiceStatus, ModelNameEnum } from './types';
|
2024-08-09 05:11:54 +00:00
|
|
|
import { Lead } from './baseModels/Lead/Lead';
|
2022-04-14 05:24:11 +00:00
|
|
|
|
2023-12-22 00:19:13 +00:00
|
|
|
export function getQuoteActions(
|
|
|
|
fyo: Fyo,
|
|
|
|
schemaName: ModelNameEnum.SalesQuote
|
|
|
|
): Action[] {
|
2023-12-22 08:50:35 +00:00
|
|
|
return [getMakeInvoiceAction(fyo, schemaName)];
|
2023-12-22 00:19:13 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 05:11:54 +00:00
|
|
|
export function getLeadActions(fyo: Fyo): Action[] {
|
|
|
|
return [getCreateCustomerAction(fyo), getSalesQuoteAction(fyo)];
|
|
|
|
}
|
|
|
|
|
2022-12-01 08:31:23 +00:00
|
|
|
export function getInvoiceActions(
|
|
|
|
fyo: Fyo,
|
|
|
|
schemaName: ModelNameEnum.SalesInvoice | ModelNameEnum.PurchaseInvoice
|
|
|
|
): Action[] {
|
2022-04-14 08:01:33 +00:00
|
|
|
return [
|
2022-11-22 09:12:49 +00:00
|
|
|
getMakePaymentAction(fyo),
|
2022-12-01 08:31:23 +00:00
|
|
|
getMakeStockTransferAction(fyo, schemaName),
|
2022-11-22 09:12:49 +00:00
|
|
|
getLedgerLinkAction(fyo),
|
2023-09-23 11:15:22 +00:00
|
|
|
getMakeReturnDocAction(fyo),
|
2022-11-22 09:12:49 +00:00
|
|
|
];
|
|
|
|
}
|
2022-05-03 13:13:47 +00:00
|
|
|
|
2023-06-05 06:09:06 +00:00
|
|
|
export function getStockTransferActions(
|
|
|
|
fyo: Fyo,
|
|
|
|
schemaName: ModelNameEnum.Shipment | ModelNameEnum.PurchaseReceipt
|
|
|
|
): Action[] {
|
|
|
|
return [
|
|
|
|
getMakeInvoiceAction(fyo, schemaName),
|
|
|
|
getLedgerLinkAction(fyo, false),
|
|
|
|
getLedgerLinkAction(fyo, true),
|
2023-07-01 07:31:00 +00:00
|
|
|
getMakeReturnDocAction(fyo),
|
2023-06-05 06:09:06 +00:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2022-12-01 08:31:23 +00:00
|
|
|
export function getMakeStockTransferAction(
|
|
|
|
fyo: Fyo,
|
|
|
|
schemaName: ModelNameEnum.SalesInvoice | ModelNameEnum.PurchaseInvoice
|
|
|
|
): Action {
|
|
|
|
let label = fyo.t`Shipment`;
|
|
|
|
if (schemaName === ModelNameEnum.PurchaseInvoice) {
|
|
|
|
label = fyo.t`Purchase Receipt`;
|
|
|
|
}
|
|
|
|
|
2022-11-22 09:12:49 +00:00
|
|
|
return {
|
2022-12-01 08:31:23 +00:00
|
|
|
label,
|
2022-11-30 06:59:52 +00:00
|
|
|
group: fyo.t`Create`,
|
2022-11-22 09:12:49 +00:00
|
|
|
condition: (doc: Doc) => doc.isSubmitted && !!doc.stockNotTransferred,
|
|
|
|
action: async (doc: Doc) => {
|
|
|
|
const transfer = await (doc as Invoice).getStockTransfer();
|
2023-06-22 08:52:54 +00:00
|
|
|
if (!transfer || !transfer.name) {
|
2022-11-22 09:12:49 +00:00
|
|
|
return;
|
|
|
|
}
|
2022-04-14 08:01:33 +00:00
|
|
|
|
2022-11-22 09:12:49 +00:00
|
|
|
const { routeTo } = await import('src/utils/ui');
|
|
|
|
const path = `/edit/${transfer.schemaName}/${transfer.name}`;
|
|
|
|
await routeTo(path);
|
2022-04-14 08:01:33 +00:00
|
|
|
},
|
2022-11-22 09:12:49 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-06-05 06:09:06 +00:00
|
|
|
export function getMakeInvoiceAction(
|
|
|
|
fyo: Fyo,
|
2023-12-22 08:50:35 +00:00
|
|
|
schemaName:
|
|
|
|
| ModelNameEnum.Shipment
|
|
|
|
| ModelNameEnum.PurchaseReceipt
|
|
|
|
| ModelNameEnum.SalesQuote
|
2023-06-05 06:09:06 +00:00
|
|
|
): Action {
|
|
|
|
let label = fyo.t`Sales Invoice`;
|
|
|
|
if (schemaName === ModelNameEnum.PurchaseReceipt) {
|
|
|
|
label = fyo.t`Purchase Invoice`;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
label,
|
|
|
|
group: fyo.t`Create`,
|
2023-12-22 00:19:13 +00:00
|
|
|
condition: (doc: Doc) => {
|
|
|
|
if (schemaName === ModelNameEnum.SalesQuote) {
|
2023-12-22 08:50:35 +00:00
|
|
|
return doc.isSubmitted;
|
2023-12-22 00:19:13 +00:00
|
|
|
} else {
|
2023-12-22 08:50:35 +00:00
|
|
|
return doc.isSubmitted && !doc.backReference;
|
2023-12-22 00:19:13 +00:00
|
|
|
}
|
|
|
|
},
|
2023-06-05 06:09:06 +00:00
|
|
|
action: async (doc: Doc) => {
|
2023-12-22 08:50:35 +00:00
|
|
|
const invoice = await (doc as SalesQuote | StockTransfer).getInvoice();
|
2023-06-22 08:52:54 +00:00
|
|
|
if (!invoice || !invoice.name) {
|
2023-06-05 06:09:06 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { routeTo } = await import('src/utils/ui');
|
|
|
|
const path = `/edit/${invoice.schemaName}/${invoice.name}`;
|
|
|
|
await routeTo(path);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-08-09 05:11:54 +00:00
|
|
|
export function getCreateCustomerAction(fyo: Fyo): Action {
|
|
|
|
return {
|
|
|
|
group: fyo.t`Create`,
|
|
|
|
label: fyo.t`Customer`,
|
|
|
|
action: async (doc: Doc, router) => {
|
2024-08-09 10:26:10 +00:00
|
|
|
const customerData = (doc as Lead).createCustomer();
|
|
|
|
|
|
|
|
if (!customerData.name) {
|
2024-08-09 05:11:54 +00:00
|
|
|
return;
|
|
|
|
}
|
2024-08-09 10:26:10 +00:00
|
|
|
await router.push(`/edit/Party/${customerData.name}`);
|
2024-08-09 05:11:54 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getSalesQuoteAction(fyo: Fyo): Action {
|
|
|
|
return {
|
|
|
|
group: fyo.t`Create`,
|
|
|
|
label: fyo.t`Sales Quote`,
|
|
|
|
action: async (doc, router) => {
|
2024-08-09 10:26:10 +00:00
|
|
|
const salesQuoteData = (doc as Lead).createSalesQuote();
|
|
|
|
if (!salesQuoteData.name) {
|
2024-08-09 05:11:54 +00:00
|
|
|
return;
|
|
|
|
}
|
2024-08-09 10:26:10 +00:00
|
|
|
await router.push(`/edit/SalesQuote/${salesQuoteData.name}`);
|
2024-08-09 05:11:54 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-11-22 09:12:49 +00:00
|
|
|
export function getMakePaymentAction(fyo: Fyo): Action {
|
|
|
|
return {
|
2022-11-30 06:59:52 +00:00
|
|
|
label: fyo.t`Payment`,
|
|
|
|
group: fyo.t`Create`,
|
2022-11-22 09:12:49 +00:00
|
|
|
condition: (doc: Doc) =>
|
|
|
|
doc.isSubmitted && !(doc.outstandingAmount as Money).isZero(),
|
2023-04-19 07:43:46 +00:00
|
|
|
action: async (doc, router) => {
|
2023-10-11 06:13:43 +00:00
|
|
|
const schemaName = doc.schema.name;
|
2022-11-22 09:12:49 +00:00
|
|
|
const payment = (doc as Invoice).getPayment();
|
|
|
|
if (!payment) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-11 06:13:43 +00:00
|
|
|
await payment?.set('referenceType', schemaName);
|
2023-04-19 07:43:46 +00:00
|
|
|
const currentRoute = router.currentRoute.value.fullPath;
|
2022-11-22 09:12:49 +00:00
|
|
|
payment.once('afterSync', async () => {
|
|
|
|
await payment.submit();
|
2023-04-19 07:43:46 +00:00
|
|
|
await doc.load();
|
|
|
|
await router.push(currentRoute);
|
2022-11-22 09:12:49 +00:00
|
|
|
});
|
|
|
|
|
2023-11-17 06:42:35 +00:00
|
|
|
const hideFields = ['party', 'for'];
|
|
|
|
|
|
|
|
if (!fyo.singles.AccountingSettings?.enableInvoiceReturns) {
|
|
|
|
hideFields.push('paymentType');
|
|
|
|
}
|
|
|
|
|
2023-04-19 07:43:46 +00:00
|
|
|
if (doc.schemaName === ModelNameEnum.SalesInvoice) {
|
|
|
|
hideFields.push('account');
|
|
|
|
} else {
|
|
|
|
hideFields.push('paymentAccount');
|
|
|
|
}
|
|
|
|
|
|
|
|
await payment.runFormulas();
|
2022-11-22 09:12:49 +00:00
|
|
|
const { openQuickEdit } = await import('src/utils/ui');
|
|
|
|
await openQuickEdit({
|
|
|
|
doc: payment,
|
2023-04-19 07:43:46 +00:00
|
|
|
hideFields,
|
2022-11-22 09:12:49 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
};
|
2022-04-14 08:01:33 +00:00
|
|
|
}
|
|
|
|
|
2023-06-22 08:52:54 +00:00
|
|
|
export function getLedgerLinkAction(fyo: Fyo, isStock = false): Action {
|
2022-12-01 08:31:23 +00:00
|
|
|
let label = fyo.t`Accounting Entries`;
|
2023-03-15 08:32:52 +00:00
|
|
|
let reportClassName: 'GeneralLedger' | 'StockLedger' = 'GeneralLedger';
|
2022-11-21 06:35:05 +00:00
|
|
|
|
|
|
|
if (isStock) {
|
|
|
|
label = fyo.t`Stock Entries`;
|
|
|
|
reportClassName = 'StockLedger';
|
|
|
|
}
|
|
|
|
|
2022-05-03 13:13:47 +00:00
|
|
|
return {
|
2022-11-21 06:35:05 +00:00
|
|
|
label,
|
2022-11-30 06:59:52 +00:00
|
|
|
group: fyo.t`View`,
|
2022-05-03 13:13:47 +00:00
|
|
|
condition: (doc: Doc) => doc.isSubmitted,
|
|
|
|
action: async (doc: Doc, router: Router) => {
|
2023-03-15 08:32:52 +00:00
|
|
|
const route = getLedgerLink(doc, reportClassName);
|
2023-06-22 08:52:54 +00:00
|
|
|
await router.push(route);
|
2023-03-15 08:32:52 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getLedgerLink(
|
|
|
|
doc: Doc,
|
|
|
|
reportClassName: 'GeneralLedger' | 'StockLedger'
|
|
|
|
) {
|
|
|
|
return {
|
|
|
|
name: 'Report',
|
|
|
|
params: {
|
|
|
|
reportClassName,
|
|
|
|
defaultFilters: JSON.stringify({
|
|
|
|
referenceType: doc.schemaName,
|
|
|
|
referenceName: doc.name,
|
|
|
|
}),
|
2022-05-03 13:13:47 +00:00
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
2023-07-01 07:31:00 +00:00
|
|
|
export function getMakeReturnDocAction(fyo: Fyo): Action {
|
|
|
|
return {
|
|
|
|
label: fyo.t`Return`,
|
|
|
|
group: fyo.t`Create`,
|
|
|
|
condition: (doc: Doc) =>
|
2023-09-23 11:15:22 +00:00
|
|
|
(!!fyo.singles.AccountingSettings?.enableInvoiceReturns ||
|
|
|
|
!!fyo.singles.InventorySettings?.enableStockReturns) &&
|
2023-07-01 07:31:00 +00:00
|
|
|
doc.isSubmitted &&
|
|
|
|
!doc.isReturn,
|
|
|
|
action: async (doc: Doc) => {
|
2023-09-23 11:15:22 +00:00
|
|
|
let returnDoc: Invoice | StockTransfer | undefined;
|
|
|
|
|
|
|
|
if (doc instanceof Invoice || doc instanceof StockTransfer) {
|
|
|
|
returnDoc = await doc.getReturnDoc();
|
|
|
|
}
|
|
|
|
|
2023-07-01 07:31:00 +00:00
|
|
|
if (!returnDoc || !returnDoc.name) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const { routeTo } = await import('src/utils/ui');
|
|
|
|
const path = `/edit/${doc.schemaName}/${returnDoc.name}`;
|
|
|
|
await routeTo(path);
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
2022-05-03 13:13:47 +00:00
|
|
|
|
2022-04-28 12:37:07 +00:00
|
|
|
export function getTransactionStatusColumn(): ColumnConfig {
|
2022-04-14 08:01:33 +00:00
|
|
|
return {
|
2022-04-28 12:37:07 +00:00
|
|
|
label: t`Status`,
|
2022-04-14 08:01:33 +00:00
|
|
|
fieldname: 'status',
|
|
|
|
fieldtype: 'Select',
|
2022-06-14 09:10:46 +00:00
|
|
|
render(doc) {
|
|
|
|
const status = getDocStatus(doc) as InvoiceStatus;
|
2023-06-22 08:52:54 +00:00
|
|
|
const color = statusColor[status] ?? 'gray';
|
2022-11-30 13:35:49 +00:00
|
|
|
const label = getStatusText(status);
|
2022-06-14 09:10:46 +00:00
|
|
|
|
2022-04-14 08:01:33 +00:00
|
|
|
return {
|
|
|
|
template: `<Badge class="text-xs" color="${color}">${label}</Badge>`,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-08-09 05:11:54 +00:00
|
|
|
export function getLeadStatusColumn(): ColumnConfig {
|
|
|
|
return {
|
|
|
|
label: t`Status`,
|
|
|
|
fieldname: 'status',
|
|
|
|
fieldtype: 'Select',
|
|
|
|
render(doc) {
|
|
|
|
const status = getLeadStatus(doc) as LeadStatus;
|
|
|
|
const color = statusColor[status] ?? 'gray';
|
|
|
|
const label = getStatusTextOfLead(status);
|
|
|
|
|
|
|
|
return {
|
|
|
|
template: `<Badge class="text-xs" color="${color}">${label}</Badge>`,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-06-14 09:10:46 +00:00
|
|
|
export const statusColor: Record<
|
2024-08-09 05:11:54 +00:00
|
|
|
DocStatus | InvoiceStatus | LeadStatus,
|
2022-06-14 09:10:46 +00:00
|
|
|
string | undefined
|
|
|
|
> = {
|
|
|
|
'': 'gray',
|
2022-04-14 08:01:33 +00:00
|
|
|
Draft: 'gray',
|
2024-08-09 05:11:54 +00:00
|
|
|
Open: 'gray',
|
|
|
|
Replied: 'yellow',
|
|
|
|
Opportunity: 'yellow',
|
2022-04-14 08:01:33 +00:00
|
|
|
Unpaid: 'orange',
|
|
|
|
Paid: 'green',
|
2024-08-09 05:11:54 +00:00
|
|
|
Interested: 'yellow',
|
|
|
|
Converted: 'green',
|
|
|
|
Quotation: 'green',
|
2022-06-14 09:10:46 +00:00
|
|
|
Saved: 'gray',
|
|
|
|
NotSaved: 'gray',
|
|
|
|
Submitted: 'green',
|
2022-04-14 08:01:33 +00:00
|
|
|
Cancelled: 'red',
|
2024-08-09 05:11:54 +00:00
|
|
|
DonotContact: 'red',
|
2023-07-31 12:21:59 +00:00
|
|
|
Return: 'green',
|
|
|
|
ReturnIssued: 'green',
|
2022-04-14 08:01:33 +00:00
|
|
|
};
|
|
|
|
|
2022-11-30 13:35:49 +00:00
|
|
|
export function getStatusText(status: DocStatus | InvoiceStatus): string {
|
|
|
|
switch (status) {
|
|
|
|
case 'Draft':
|
|
|
|
return t`Draft`;
|
|
|
|
case 'Saved':
|
|
|
|
return t`Saved`;
|
|
|
|
case 'NotSaved':
|
2023-01-04 12:23:42 +00:00
|
|
|
return t`Not Saved`;
|
2022-11-30 13:35:49 +00:00
|
|
|
case 'Submitted':
|
|
|
|
return t`Submitted`;
|
|
|
|
case 'Cancelled':
|
|
|
|
return t`Cancelled`;
|
|
|
|
case 'Paid':
|
|
|
|
return t`Paid`;
|
|
|
|
case 'Unpaid':
|
|
|
|
return t`Unpaid`;
|
2023-07-01 07:31:00 +00:00
|
|
|
case 'Return':
|
|
|
|
return t`Return`;
|
|
|
|
case 'ReturnIssued':
|
|
|
|
return t`Return Issued`;
|
2022-11-30 13:35:49 +00:00
|
|
|
default:
|
|
|
|
return '';
|
|
|
|
}
|
2022-06-14 09:10:46 +00:00
|
|
|
}
|
|
|
|
|
2024-08-09 05:11:54 +00:00
|
|
|
export function getStatusTextOfLead(status: LeadStatus): string {
|
|
|
|
switch (status) {
|
|
|
|
case 'Open':
|
|
|
|
return t`Open`;
|
|
|
|
case 'Replied':
|
|
|
|
return t`Replied`;
|
|
|
|
case 'Opportunity':
|
|
|
|
return t`Opportunity`;
|
|
|
|
case 'Interested':
|
|
|
|
return t`Interested`;
|
|
|
|
case 'Converted':
|
|
|
|
return t`Converted`;
|
|
|
|
case 'Quotation':
|
|
|
|
return t`Quotation`;
|
|
|
|
case 'DonotContact':
|
|
|
|
return t`Do not Contact`;
|
|
|
|
default:
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getLeadStatus(
|
|
|
|
doc?: Lead | Doc | RenderData
|
|
|
|
): LeadStatus | DocStatus {
|
|
|
|
if (!doc) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
return doc.status as LeadStatus;
|
|
|
|
}
|
|
|
|
|
2022-06-14 09:10:46 +00:00
|
|
|
export function getDocStatus(
|
|
|
|
doc?: RenderData | Doc
|
|
|
|
): DocStatus | InvoiceStatus {
|
|
|
|
if (!doc) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doc.notInserted) {
|
|
|
|
return 'Draft';
|
2022-04-14 08:01:33 +00:00
|
|
|
}
|
|
|
|
|
2022-06-14 09:10:46 +00:00
|
|
|
if (doc.dirty) {
|
|
|
|
return 'NotSaved';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!doc.schema?.isSubmittable) {
|
|
|
|
return 'Saved';
|
|
|
|
}
|
|
|
|
|
|
|
|
return getSubmittableDocStatus(doc);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getSubmittableDocStatus(doc: RenderData | Doc) {
|
|
|
|
if (
|
|
|
|
[ModelNameEnum.SalesInvoice, ModelNameEnum.PurchaseInvoice].includes(
|
|
|
|
doc.schema.name as ModelNameEnum
|
|
|
|
)
|
|
|
|
) {
|
|
|
|
return getInvoiceStatus(doc);
|
|
|
|
}
|
|
|
|
|
2023-07-01 07:31:00 +00:00
|
|
|
if (
|
|
|
|
[ModelNameEnum.Shipment, ModelNameEnum.PurchaseReceipt].includes(
|
2023-08-01 05:42:13 +00:00
|
|
|
doc.schema.name as ModelNameEnum
|
2023-07-01 07:31:00 +00:00
|
|
|
)
|
|
|
|
) {
|
2023-08-01 05:42:13 +00:00
|
|
|
if (!!doc.returnAgainst && doc.submitted && !doc.cancelled) {
|
2023-07-01 07:31:00 +00:00
|
|
|
return 'Return';
|
|
|
|
}
|
|
|
|
|
2023-08-01 05:42:13 +00:00
|
|
|
if (doc.isReturned && doc.submitted && !doc.cancelled) {
|
2023-07-01 07:31:00 +00:00
|
|
|
return 'ReturnIssued';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-14 09:10:46 +00:00
|
|
|
if (!!doc.submitted && !doc.cancelled) {
|
|
|
|
return 'Submitted';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!!doc.submitted && !!doc.cancelled) {
|
|
|
|
return 'Cancelled';
|
|
|
|
}
|
|
|
|
|
|
|
|
return 'Saved';
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getInvoiceStatus(doc: RenderData | Doc): InvoiceStatus {
|
2023-09-23 11:15:22 +00:00
|
|
|
if (doc.submitted && !doc.cancelled && doc.returnAgainst) {
|
|
|
|
return 'Return';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doc.submitted && !doc.cancelled && doc.isReturned) {
|
|
|
|
return 'ReturnIssued';
|
|
|
|
}
|
|
|
|
|
2022-06-14 09:10:46 +00:00
|
|
|
if (
|
|
|
|
doc.submitted &&
|
|
|
|
!doc.cancelled &&
|
|
|
|
(doc.outstandingAmount as Money).isZero()
|
|
|
|
) {
|
|
|
|
return 'Paid';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
doc.submitted &&
|
|
|
|
!doc.cancelled &&
|
|
|
|
(doc.outstandingAmount as Money).isPositive()
|
|
|
|
) {
|
|
|
|
return 'Unpaid';
|
2022-04-14 08:01:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (doc.cancelled) {
|
2022-06-14 09:10:46 +00:00
|
|
|
return 'Cancelled';
|
2022-04-14 08:01:33 +00:00
|
|
|
}
|
2022-06-14 09:10:46 +00:00
|
|
|
|
|
|
|
return 'Saved';
|
2022-04-14 08:01:33 +00:00
|
|
|
}
|
2022-04-19 06:05:39 +00:00
|
|
|
|
2023-05-04 10:45:12 +00:00
|
|
|
export function getSerialNumberStatusColumn(): ColumnConfig {
|
2023-04-25 07:07:29 +00:00
|
|
|
return {
|
|
|
|
label: t`Status`,
|
|
|
|
fieldname: 'status',
|
|
|
|
fieldtype: 'Select',
|
|
|
|
render(doc) {
|
2023-05-04 10:45:12 +00:00
|
|
|
let status = doc.status;
|
|
|
|
if (typeof status !== 'string') {
|
|
|
|
status = 'Inactive';
|
|
|
|
}
|
|
|
|
|
|
|
|
const color = serialNumberStatusColor[status] ?? 'gray';
|
|
|
|
const label = getSerialNumberStatusText(status);
|
2023-04-25 07:07:29 +00:00
|
|
|
|
|
|
|
return {
|
|
|
|
template: `<Badge class="text-xs" color="${color}">${label}</Badge>`,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-05-04 10:45:12 +00:00
|
|
|
export const serialNumberStatusColor: Record<string, string | undefined> = {
|
2023-04-25 07:07:29 +00:00
|
|
|
Inactive: 'gray',
|
|
|
|
Active: 'green',
|
2023-05-04 10:45:12 +00:00
|
|
|
Delivered: 'blue',
|
2023-04-25 07:07:29 +00:00
|
|
|
};
|
|
|
|
|
2023-05-04 10:45:12 +00:00
|
|
|
export function getSerialNumberStatusText(status: string): string {
|
2023-04-25 07:07:29 +00:00
|
|
|
switch (status) {
|
|
|
|
case 'Inactive':
|
|
|
|
return t`Inactive`;
|
|
|
|
case 'Active':
|
|
|
|
return t`Active`;
|
|
|
|
case 'Delivered':
|
|
|
|
return t`Delivered`;
|
|
|
|
default:
|
|
|
|
return t`Inactive`;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-06 08:59:08 +00:00
|
|
|
export function getPriceListStatusColumn(): ColumnConfig {
|
|
|
|
return {
|
|
|
|
label: t`Enabled For`,
|
|
|
|
fieldname: 'enabledFor',
|
|
|
|
fieldtype: 'Select',
|
2023-06-07 04:45:26 +00:00
|
|
|
render({ isSales, isPurchase }) {
|
2023-06-06 22:39:46 +00:00
|
|
|
let status = t`None`;
|
2023-06-06 08:59:08 +00:00
|
|
|
|
2023-06-07 04:45:26 +00:00
|
|
|
if (isSales && isPurchase) {
|
|
|
|
status = t`Sales and Purchase`;
|
|
|
|
} else if (isSales) {
|
|
|
|
status = t`Sales`;
|
|
|
|
} else if (isPurchase) {
|
|
|
|
status = t`Purchase`;
|
2023-06-06 08:59:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
template: `<Badge class="text-xs" color="gray">${status}</Badge>`,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2023-06-06 22:42:38 +00:00
|
|
|
export function getPriceListEnabledColumn(): ColumnConfig {
|
|
|
|
return {
|
|
|
|
label: t`Enabled`,
|
|
|
|
fieldname: 'enabled',
|
|
|
|
fieldtype: 'Data',
|
|
|
|
render(doc) {
|
2023-06-07 04:45:26 +00:00
|
|
|
let status = t`Disabled`;
|
2023-06-06 22:42:38 +00:00
|
|
|
let color = 'orange';
|
2023-06-07 04:45:26 +00:00
|
|
|
if (doc.isEnabled) {
|
2023-06-06 22:42:38 +00:00
|
|
|
status = t`Enabled`;
|
|
|
|
color = 'green';
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
template: `<Badge class="text-xs" color="${color}">${status}</Badge>`,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-04-19 06:05:39 +00:00
|
|
|
export async function getExchangeRate({
|
|
|
|
fromCurrency,
|
|
|
|
toCurrency,
|
|
|
|
date,
|
|
|
|
}: {
|
|
|
|
fromCurrency: string;
|
|
|
|
toCurrency: string;
|
|
|
|
date?: string;
|
|
|
|
}) {
|
2022-09-29 09:41:05 +00:00
|
|
|
if (!fetch) {
|
|
|
|
return 1;
|
2022-04-19 06:05:39 +00:00
|
|
|
}
|
|
|
|
|
2022-09-29 09:41:05 +00:00
|
|
|
if (!date) {
|
|
|
|
date = DateTime.local().toISODate();
|
2022-04-19 06:05:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const cacheKey = `currencyExchangeRate:${date}:${fromCurrency}:${toCurrency}`;
|
|
|
|
|
|
|
|
let exchangeRate = 0;
|
|
|
|
if (localStorage) {
|
2023-06-22 08:52:54 +00:00
|
|
|
exchangeRate = safeParseFloat(localStorage.getItem(cacheKey) as string);
|
2022-04-19 06:05:39 +00:00
|
|
|
}
|
|
|
|
|
2022-09-29 09:41:05 +00:00
|
|
|
if (exchangeRate && exchangeRate !== 1) {
|
|
|
|
return exchangeRate;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const res = await fetch(
|
|
|
|
`https://api.vatcomply.com/rates?date=${date}&base=${fromCurrency}&symbols=${toCurrency}`
|
|
|
|
);
|
2023-06-22 08:52:54 +00:00
|
|
|
const data = (await res.json()) as {
|
|
|
|
base: string;
|
|
|
|
data: string;
|
|
|
|
rates: Record<string, number>;
|
|
|
|
};
|
2022-09-29 09:41:05 +00:00
|
|
|
exchangeRate = data.rates[toCurrency];
|
|
|
|
} catch (error) {
|
2023-06-22 08:52:54 +00:00
|
|
|
// eslint-disable-next-line no-console
|
2022-09-29 09:41:05 +00:00
|
|
|
console.error(error);
|
|
|
|
exchangeRate ??= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (localStorage) {
|
|
|
|
localStorage.setItem(cacheKey, String(exchangeRate));
|
2022-04-19 06:05:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return exchangeRate;
|
|
|
|
}
|
2022-05-14 08:46:05 +00:00
|
|
|
|
|
|
|
export function isCredit(rootType: AccountRootType) {
|
|
|
|
switch (rootType) {
|
|
|
|
case AccountRootTypeEnum.Asset:
|
|
|
|
return false;
|
|
|
|
case AccountRootTypeEnum.Liability:
|
|
|
|
return true;
|
|
|
|
case AccountRootTypeEnum.Equity:
|
|
|
|
return true;
|
|
|
|
case AccountRootTypeEnum.Expense:
|
|
|
|
return false;
|
|
|
|
case AccountRootTypeEnum.Income:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2022-10-12 09:29:43 +00:00
|
|
|
|
|
|
|
export function getNumberSeries(schemaName: string, fyo: Fyo) {
|
|
|
|
const numberSeriesKey = numberSeriesDefaultsMap[schemaName];
|
|
|
|
if (!numberSeriesKey) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
|
2023-06-22 08:52:54 +00:00
|
|
|
const defaults = fyo.singles.Defaults;
|
2022-10-12 09:29:43 +00:00
|
|
|
const field = fyo.getField(schemaName, 'numberSeries');
|
|
|
|
const value = defaults?.[numberSeriesKey] as string | undefined;
|
|
|
|
return value ?? (field?.default as string | undefined);
|
|
|
|
}
|
2022-11-16 08:35:38 +00:00
|
|
|
|
|
|
|
export function getDocStatusListColumn(): ColumnConfig {
|
|
|
|
return {
|
|
|
|
label: t`Status`,
|
|
|
|
fieldname: 'status',
|
|
|
|
fieldtype: 'Select',
|
|
|
|
render(doc) {
|
|
|
|
const status = getDocStatus(doc);
|
|
|
|
const color = statusColor[status] ?? 'gray';
|
2022-11-30 13:35:49 +00:00
|
|
|
const label = getStatusText(status);
|
2022-11-16 08:35:38 +00:00
|
|
|
|
|
|
|
return {
|
|
|
|
template: `<Badge class="text-xs" color="${color}">${label}</Badge>`,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
2023-01-16 09:38:02 +00:00
|
|
|
|
|
|
|
type ModelsWithItems = Invoice | StockTransfer | StockMovement;
|
|
|
|
export async function addItem<M extends ModelsWithItems>(name: string, doc: M) {
|
|
|
|
if (!doc.canEdit) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const items = (doc.items ?? []) as NonNullable<M['items']>[number][];
|
|
|
|
|
|
|
|
let item = items.find((i) => i.item === name);
|
|
|
|
if (item) {
|
|
|
|
const q = item.quantity ?? 0;
|
|
|
|
await item.set('quantity', q + 1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
await doc.append('items');
|
|
|
|
item = doc.items?.at(-1);
|
|
|
|
if (!item) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
await item.set('item', name);
|
|
|
|
}
|