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: #151 Quotations #788

Merged
merged 3 commits into from
Jan 8, 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
2 changes: 2 additions & 0 deletions backend/patches/updateSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const defaultNumberSeriesMap = {
[ModelNameEnum.JournalEntry]: 'JV-',
[ModelNameEnum.SalesInvoice]: 'SINV-',
[ModelNameEnum.PurchaseInvoice]: 'PINV-',
[ModelNameEnum.SalesQuote]: 'SQUOT-',
} as Record<ModelNameEnum, string>;

async function execute(dm: DatabaseManager) {
Expand Down Expand Up @@ -209,6 +210,7 @@ async function copyTransactionalTables(
ModelNameEnum.Payment,
ModelNameEnum.SalesInvoice,
ModelNameEnum.PurchaseInvoice,
ModelNameEnum.SalesQuote,
];

for (const sn of schemaNames) {
Expand Down
7 changes: 7 additions & 0 deletions models/baseModels/Defaults/Defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export class Defaults extends Doc {
purchaseReceiptLocation?: string;

// Number Series
salesQuoteNumberSeries?: string;
salesInvoiceNumberSeries?: string;
purchaseInvoiceNumberSeries?: string;
journalEntryNumberSeries?: string;
Expand All @@ -29,6 +30,7 @@ export class Defaults extends Doc {
purchaseReceiptTerms?: string;

// Print Templates
salesQuotePrintTemplate?: string;
salesInvoicePrintTemplate?: string;
purchaseInvoicePrintTemplate?: string;
journalEntryPrintTemplate?: string;
Expand All @@ -46,6 +48,9 @@ export class Defaults extends Doc {
salesPaymentAccount: () => ({ isGroup: false, accountType: 'Cash' }),
purchasePaymentAccount: () => ({ isGroup: false, accountType: 'Cash' }),
// Number Series
salesQuoteNumberSeries: () => ({
referenceType: ModelNameEnum.SalesQuote,
}),
salesInvoiceNumberSeries: () => ({
referenceType: ModelNameEnum.SalesInvoice,
}),
Expand All @@ -68,6 +73,7 @@ export class Defaults extends Doc {
referenceType: ModelNameEnum.PurchaseReceipt,
}),
// Print Templates
salesQuotePrintTemplate: () => ({ type: ModelNameEnum.SalesQuote }),
salesInvoicePrintTemplate: () => ({ type: ModelNameEnum.SalesInvoice }),
purchaseInvoicePrintTemplate: () => ({
type: ModelNameEnum.PurchaseInvoice,
Expand Down Expand Up @@ -118,4 +124,5 @@ export const numberSeriesDefaultsMap: Record<
[ModelNameEnum.StockMovement]: 'stockMovementNumberSeries',
[ModelNameEnum.Shipment]: 'shipmentNumberSeries',
[ModelNameEnum.PurchaseReceipt]: 'purchaseReceiptNumberSeries',
[ModelNameEnum.SalesQuote]: 'salesQuoteNumberSeries',
};
13 changes: 10 additions & 3 deletions models/baseModels/Invoice/Invoice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,13 @@ export abstract class Invoice extends Transactional {
returnAgainst?: string;

get isSales() {
return this.schemaName === 'SalesInvoice';
return (
this.schemaName === 'SalesInvoice' || this.schemaName == 'SalesQuote'
);
}

get isQuote() {
return this.schemaName == 'SalesQuote';
}

get enableDiscounting() {
Expand Down Expand Up @@ -493,7 +499,7 @@ export abstract class Invoice extends Transactional {
}

async _updateIsItemsReturned() {
if (!this.isReturn || !this.returnAgainst) {
if (!this.isReturn || !this.returnAgainst || this.isQuote) {
return;
}

Expand All @@ -515,7 +521,7 @@ export abstract class Invoice extends Transactional {
}

async _validateHasLinkedReturnInvoices() {
if (!this.name || this.isReturn) {
if (!this.name || this.isReturn || this.isQuote) {
return;
}

Expand Down Expand Up @@ -685,6 +691,7 @@ export abstract class Invoice extends Transactional {
attachment: () =>
!(this.attachment || !(this.isSubmitted || this.isCancelled)),
backReference: () => !this.backReference,
quote: () => !this.quote,
priceList: () => !this.fyo.singles.AccountingSettings?.enablePriceList,
returnAgainst: () =>
(this.isSubmitted || this.isCancelled) && !this.returnAgainst,
Expand Down
5 changes: 4 additions & 1 deletion models/baseModels/InvoiceItem/InvoiceItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ export abstract class InvoiceItem extends Doc {
itemTaxedTotal?: Money;

get isSales() {
return this.schemaName === 'SalesInvoiceItem';
return (
this.schemaName === 'SalesInvoiceItem' ||
this.schemaName === 'SalesQuoteItem'
);
}

get date() {
Expand Down
1 change: 1 addition & 0 deletions models/baseModels/PrintTemplate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export class PrintTemplate extends Doc {

const models = [
ModelNameEnum.SalesInvoice,
ModelNameEnum.SalesQuote,
ModelNameEnum.PurchaseInvoice,
ModelNameEnum.JournalEntry,
ModelNameEnum.Payment,
Expand Down
67 changes: 67 additions & 0 deletions models/baseModels/SalesQuote/SalesQuote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Fyo } from 'fyo';
import { DocValueMap } from 'fyo/core/types';
import { Action, ListViewSettings } from 'fyo/model/types';
import { ModelNameEnum } from 'models/types';
import { getQuoteActions, getTransactionStatusColumn } from '../../helpers';
import { Invoice } from '../Invoice/Invoice';
import { SalesQuoteItem } from '../SalesQuoteItem/SalesQuoteItem';
import { Defaults } from '../Defaults/Defaults';

export class SalesQuote extends Invoice {
items?: SalesQuoteItem[];

// This is an inherited method and it must keep the async from the parent
// class
// eslint-disable-next-line @typescript-eslint/require-await
async getPosting() {
return null;
}

async getInvoice(): Promise<Invoice | null> {
if (!this.isSubmitted) {
return null;
}

const schemaName = ModelNameEnum.SalesInvoice;
const defaults = (this.fyo.singles.Defaults as Defaults) ?? {};
const terms = defaults.salesInvoiceTerms ?? '';
const numberSeries = defaults.salesInvoiceNumberSeries ?? undefined;

const data: DocValueMap = {
...this.getValidDict(false, true),
date: new Date().toISOString(),
terms,
numberSeries,
quote: this.name,
items: [],
};

const invoice = this.fyo.doc.getNewDoc(schemaName, data) as Invoice;
for (const row of this.items ?? []) {
await invoice.append('items', row.getValidDict(false, true));
}

if (!invoice.items?.length) {
return null;
}

return invoice;
}

static getListViewSettings(): ListViewSettings {
return {
columns: [
'name',
getTransactionStatusColumn(),
'party',
'date',
'baseGrandTotal',
'outstandingAmount',
],
};
}

static getActions(fyo: Fyo): Action[] {
return getQuoteActions(fyo, ModelNameEnum.SalesQuote);
}
}
3 changes: 3 additions & 0 deletions models/baseModels/SalesQuoteItem/SalesQuoteItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { InvoiceItem } from '../InvoiceItem/InvoiceItem';

export class SalesQuoteItem extends InvoiceItem {}
23 changes: 20 additions & 3 deletions models/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,18 @@ import {
} from './baseModels/Account/types';
import { numberSeriesDefaultsMap } from './baseModels/Defaults/Defaults';
import { Invoice } from './baseModels/Invoice/Invoice';
import { SalesQuote } from './baseModels/SalesQuote/SalesQuote';
import { StockMovement } from './inventory/StockMovement';
import { StockTransfer } from './inventory/StockTransfer';
import { InvoiceStatus, ModelNameEnum } from './types';

export function getQuoteActions(
fyo: Fyo,
schemaName: ModelNameEnum.SalesQuote
): Action[] {
return [getMakeInvoiceAction(fyo, schemaName)];
}

export function getInvoiceActions(
fyo: Fyo,
schemaName: ModelNameEnum.SalesInvoice | ModelNameEnum.PurchaseInvoice
Expand Down Expand Up @@ -67,7 +75,10 @@ export function getMakeStockTransferAction(

export function getMakeInvoiceAction(
fyo: Fyo,
schemaName: ModelNameEnum.Shipment | ModelNameEnum.PurchaseReceipt
schemaName:
| ModelNameEnum.Shipment
| ModelNameEnum.PurchaseReceipt
| ModelNameEnum.SalesQuote
): Action {
let label = fyo.t`Sales Invoice`;
if (schemaName === ModelNameEnum.PurchaseReceipt) {
Expand All @@ -77,9 +88,15 @@ export function getMakeInvoiceAction(
return {
label,
group: fyo.t`Create`,
condition: (doc: Doc) => doc.isSubmitted && !doc.backReference,
condition: (doc: Doc) => {
if (schemaName === ModelNameEnum.SalesQuote) {
return doc.isSubmitted;
} else {
return doc.isSubmitted && !doc.backReference;
}
},
action: async (doc: Doc) => {
const invoice = await (doc as StockTransfer).getInvoice();
const invoice = await (doc as SalesQuote | StockTransfer).getInvoice();
if (!invoice || !invoice.name) {
return;
}
Expand Down
4 changes: 4 additions & 0 deletions models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { PurchaseInvoice } from './baseModels/PurchaseInvoice/PurchaseInvoice';
import { PurchaseInvoiceItem } from './baseModels/PurchaseInvoiceItem/PurchaseInvoiceItem';
import { SalesInvoice } from './baseModels/SalesInvoice/SalesInvoice';
import { SalesInvoiceItem } from './baseModels/SalesInvoiceItem/SalesInvoiceItem';
import { SalesQuote } from './baseModels/SalesQuote/SalesQuote';
import { SalesQuoteItem } from './baseModels/SalesQuoteItem/SalesQuoteItem';
import { SetupWizard } from './baseModels/SetupWizard/SetupWizard';
import { Tax } from './baseModels/Tax/Tax';
import { TaxSummary } from './baseModels/TaxSummary/TaxSummary';
Expand Down Expand Up @@ -61,6 +63,8 @@ export const models = {
PurchaseInvoiceItem,
SalesInvoice,
SalesInvoiceItem,
SalesQuote,
SalesQuoteItem,
SerialNumber,
SetupWizard,
PrintTemplate,
Expand Down
2 changes: 2 additions & 0 deletions models/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export enum ModelNameEnum {
PurchaseInvoiceItem = 'PurchaseInvoiceItem',
SalesInvoice = 'SalesInvoice',
SalesInvoiceItem = 'SalesInvoiceItem',
SalesQuote = 'SalesQuote',
SalesQuoteItem = 'SalesQuoteItem',
SerialNumber = 'SerialNumber',
SetupWizard = 'SetupWizard',
Tax = 'Tax',
Expand Down
15 changes: 15 additions & 0 deletions schemas/app/Defaults.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@
"create": true,
"section": "Number Series"
},
{
"fieldname": "salesQuoteNumberSeries",
"label": "Sales Quote Number Series",
"fieldtype": "Link",
"target": "NumberSeries",
"create": true,
"section": "Number Series"
},
{
"fieldname": "salesInvoiceTerms",
"label": "Sales Invoice Terms",
Expand All @@ -116,6 +124,13 @@
"fieldtype": "Text",
"section": "Terms"
},
{
"fieldname": "salesQuotePrintTemplate",
"label": "Sales Quote Print Template",
"fieldtype": "Link",
"target": "PrintTemplate",
"section": "Print Templates"
},
{
"fieldname": "salesInvoicePrintTemplate",
"label": "Sales Invoice Print Template",
Expand Down
4 changes: 4 additions & 0 deletions schemas/app/NumberSeries.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@
"value": "SalesInvoice",
"label": "Sales Invoice"
},
{
"value": "SalesQuote",
"label": "Sales Quote"
},
{
"value": "PurchaseInvoice",
"label": "Purchase Invoice"
Expand Down
8 changes: 8 additions & 0 deletions schemas/app/SalesInvoice.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@
"target": "Shipment",
"section": "References"
},
{
"fieldname": "quote",
"label": "Quote Reference",
"fieldtype": "Link",
"target": "SalesQuote",
"section": "References",
"required": false
},
{
"fieldname": "makeAutoStockTransfer",
"label": "Make Shipment On Submit",
Expand Down
46 changes: 46 additions & 0 deletions schemas/app/SalesQuote.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"name": "SalesQuote",
"label": "Quote",
"extends": "Invoice",
"naming": "numberSeries",
"showTitle": true,
"fields": [
{
"fieldname": "numberSeries",
"label": "Number Series",
"fieldtype": "Link",
"target": "NumberSeries",
"create": true,
"required": true,
"default": "SQUOT-",
"section": "Default"
},
{
"fieldname": "party",
"label": "Customer",
"fieldtype": "Link",
"target": "Party",
"create": true,
"required": true,
"section": "Default"
},
{
"fieldname": "items",
"label": "Items",
"fieldtype": "Table",
"target": "SalesQuoteItem",
"required": true,
"edit": true,
"section": "Items"
}
],
"keywordFields": ["name", "party"],
"removeFields": [
"account",
"stockNotTransferred",
"backReference",
"makeAutoStockTransfer",
"returnAgainst",
"isReturned"
]
}
5 changes: 5 additions & 0 deletions schemas/app/SalesQuoteItem.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "SalesQuoteItem",
"label": "Sales Quote Item",
"extends": "InvoiceItem"
}
4 changes: 4 additions & 0 deletions schemas/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import PurchaseInvoice from './app/PurchaseInvoice.json';
import PurchaseInvoiceItem from './app/PurchaseInvoiceItem.json';
import SalesInvoice from './app/SalesInvoice.json';
import SalesInvoiceItem from './app/SalesInvoiceItem.json';
import SalesQuote from './app/SalesQuote.json';
import SalesQuoteItem from './app/SalesQuoteItem.json';
import SetupWizard from './app/SetupWizard.json';
import Tax from './app/Tax.json';
import TaxDetail from './app/TaxDetail.json';
Expand Down Expand Up @@ -108,10 +110,12 @@ export const appSchemas: Schema[] | SchemaStub[] = [
Invoice as Schema,
SalesInvoice as Schema,
PurchaseInvoice as Schema,
SalesQuote as Schema,

InvoiceItem as Schema,
SalesInvoiceItem as SchemaStub,
PurchaseInvoiceItem as SchemaStub,
SalesQuoteItem as SchemaStub,

PriceList as Schema,
PriceListItem as SchemaStub,
Expand Down
Loading
Loading