mirror of
https://github.com/frappe/books.git
synced 2024-11-09 23:30:56 +00:00
Merge pull request #788 from frappe/mildred/151-quotations
feat: #151 Quotations
This commit is contained in:
commit
bcd0cc8d61
@ -21,6 +21,7 @@ const defaultNumberSeriesMap = {
|
|||||||
[ModelNameEnum.JournalEntry]: 'JV-',
|
[ModelNameEnum.JournalEntry]: 'JV-',
|
||||||
[ModelNameEnum.SalesInvoice]: 'SINV-',
|
[ModelNameEnum.SalesInvoice]: 'SINV-',
|
||||||
[ModelNameEnum.PurchaseInvoice]: 'PINV-',
|
[ModelNameEnum.PurchaseInvoice]: 'PINV-',
|
||||||
|
[ModelNameEnum.SalesQuote]: 'SQUOT-',
|
||||||
} as Record<ModelNameEnum, string>;
|
} as Record<ModelNameEnum, string>;
|
||||||
|
|
||||||
async function execute(dm: DatabaseManager) {
|
async function execute(dm: DatabaseManager) {
|
||||||
@ -209,6 +210,7 @@ async function copyTransactionalTables(
|
|||||||
ModelNameEnum.Payment,
|
ModelNameEnum.Payment,
|
||||||
ModelNameEnum.SalesInvoice,
|
ModelNameEnum.SalesInvoice,
|
||||||
ModelNameEnum.PurchaseInvoice,
|
ModelNameEnum.PurchaseInvoice,
|
||||||
|
ModelNameEnum.SalesQuote,
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const sn of schemaNames) {
|
for (const sn of schemaNames) {
|
||||||
|
@ -14,6 +14,7 @@ export class Defaults extends Doc {
|
|||||||
purchaseReceiptLocation?: string;
|
purchaseReceiptLocation?: string;
|
||||||
|
|
||||||
// Number Series
|
// Number Series
|
||||||
|
salesQuoteNumberSeries?: string;
|
||||||
salesInvoiceNumberSeries?: string;
|
salesInvoiceNumberSeries?: string;
|
||||||
purchaseInvoiceNumberSeries?: string;
|
purchaseInvoiceNumberSeries?: string;
|
||||||
journalEntryNumberSeries?: string;
|
journalEntryNumberSeries?: string;
|
||||||
@ -29,6 +30,7 @@ export class Defaults extends Doc {
|
|||||||
purchaseReceiptTerms?: string;
|
purchaseReceiptTerms?: string;
|
||||||
|
|
||||||
// Print Templates
|
// Print Templates
|
||||||
|
salesQuotePrintTemplate?: string;
|
||||||
salesInvoicePrintTemplate?: string;
|
salesInvoicePrintTemplate?: string;
|
||||||
purchaseInvoicePrintTemplate?: string;
|
purchaseInvoicePrintTemplate?: string;
|
||||||
journalEntryPrintTemplate?: string;
|
journalEntryPrintTemplate?: string;
|
||||||
@ -46,6 +48,9 @@ export class Defaults extends Doc {
|
|||||||
salesPaymentAccount: () => ({ isGroup: false, accountType: 'Cash' }),
|
salesPaymentAccount: () => ({ isGroup: false, accountType: 'Cash' }),
|
||||||
purchasePaymentAccount: () => ({ isGroup: false, accountType: 'Cash' }),
|
purchasePaymentAccount: () => ({ isGroup: false, accountType: 'Cash' }),
|
||||||
// Number Series
|
// Number Series
|
||||||
|
salesQuoteNumberSeries: () => ({
|
||||||
|
referenceType: ModelNameEnum.SalesQuote,
|
||||||
|
}),
|
||||||
salesInvoiceNumberSeries: () => ({
|
salesInvoiceNumberSeries: () => ({
|
||||||
referenceType: ModelNameEnum.SalesInvoice,
|
referenceType: ModelNameEnum.SalesInvoice,
|
||||||
}),
|
}),
|
||||||
@ -68,6 +73,7 @@ export class Defaults extends Doc {
|
|||||||
referenceType: ModelNameEnum.PurchaseReceipt,
|
referenceType: ModelNameEnum.PurchaseReceipt,
|
||||||
}),
|
}),
|
||||||
// Print Templates
|
// Print Templates
|
||||||
|
salesQuotePrintTemplate: () => ({ type: ModelNameEnum.SalesQuote }),
|
||||||
salesInvoicePrintTemplate: () => ({ type: ModelNameEnum.SalesInvoice }),
|
salesInvoicePrintTemplate: () => ({ type: ModelNameEnum.SalesInvoice }),
|
||||||
purchaseInvoicePrintTemplate: () => ({
|
purchaseInvoicePrintTemplate: () => ({
|
||||||
type: ModelNameEnum.PurchaseInvoice,
|
type: ModelNameEnum.PurchaseInvoice,
|
||||||
@ -118,4 +124,5 @@ export const numberSeriesDefaultsMap: Record<
|
|||||||
[ModelNameEnum.StockMovement]: 'stockMovementNumberSeries',
|
[ModelNameEnum.StockMovement]: 'stockMovementNumberSeries',
|
||||||
[ModelNameEnum.Shipment]: 'shipmentNumberSeries',
|
[ModelNameEnum.Shipment]: 'shipmentNumberSeries',
|
||||||
[ModelNameEnum.PurchaseReceipt]: 'purchaseReceiptNumberSeries',
|
[ModelNameEnum.PurchaseReceipt]: 'purchaseReceiptNumberSeries',
|
||||||
|
[ModelNameEnum.SalesQuote]: 'salesQuoteNumberSeries',
|
||||||
};
|
};
|
||||||
|
@ -71,7 +71,13 @@ export abstract class Invoice extends Transactional {
|
|||||||
returnAgainst?: string;
|
returnAgainst?: string;
|
||||||
|
|
||||||
get isSales() {
|
get isSales() {
|
||||||
return this.schemaName === 'SalesInvoice';
|
return (
|
||||||
|
this.schemaName === 'SalesInvoice' || this.schemaName == 'SalesQuote'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get isQuote() {
|
||||||
|
return this.schemaName == 'SalesQuote';
|
||||||
}
|
}
|
||||||
|
|
||||||
get enableDiscounting() {
|
get enableDiscounting() {
|
||||||
@ -493,7 +499,7 @@ export abstract class Invoice extends Transactional {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _updateIsItemsReturned() {
|
async _updateIsItemsReturned() {
|
||||||
if (!this.isReturn || !this.returnAgainst) {
|
if (!this.isReturn || !this.returnAgainst || this.isQuote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,7 +521,7 @@ export abstract class Invoice extends Transactional {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _validateHasLinkedReturnInvoices() {
|
async _validateHasLinkedReturnInvoices() {
|
||||||
if (!this.name || this.isReturn) {
|
if (!this.name || this.isReturn || this.isQuote) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -685,6 +691,7 @@ export abstract class Invoice extends Transactional {
|
|||||||
attachment: () =>
|
attachment: () =>
|
||||||
!(this.attachment || !(this.isSubmitted || this.isCancelled)),
|
!(this.attachment || !(this.isSubmitted || this.isCancelled)),
|
||||||
backReference: () => !this.backReference,
|
backReference: () => !this.backReference,
|
||||||
|
quote: () => !this.quote,
|
||||||
priceList: () => !this.fyo.singles.AccountingSettings?.enablePriceList,
|
priceList: () => !this.fyo.singles.AccountingSettings?.enablePriceList,
|
||||||
returnAgainst: () =>
|
returnAgainst: () =>
|
||||||
(this.isSubmitted || this.isCancelled) && !this.returnAgainst,
|
(this.isSubmitted || this.isCancelled) && !this.returnAgainst,
|
||||||
|
@ -47,7 +47,10 @@ export abstract class InvoiceItem extends Doc {
|
|||||||
itemTaxedTotal?: Money;
|
itemTaxedTotal?: Money;
|
||||||
|
|
||||||
get isSales() {
|
get isSales() {
|
||||||
return this.schemaName === 'SalesInvoiceItem';
|
return (
|
||||||
|
this.schemaName === 'SalesInvoiceItem' ||
|
||||||
|
this.schemaName === 'SalesQuoteItem'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
get date() {
|
get date() {
|
||||||
|
@ -55,6 +55,7 @@ export class PrintTemplate extends Doc {
|
|||||||
|
|
||||||
const models = [
|
const models = [
|
||||||
ModelNameEnum.SalesInvoice,
|
ModelNameEnum.SalesInvoice,
|
||||||
|
ModelNameEnum.SalesQuote,
|
||||||
ModelNameEnum.PurchaseInvoice,
|
ModelNameEnum.PurchaseInvoice,
|
||||||
ModelNameEnum.JournalEntry,
|
ModelNameEnum.JournalEntry,
|
||||||
ModelNameEnum.Payment,
|
ModelNameEnum.Payment,
|
||||||
|
67
models/baseModels/SalesQuote/SalesQuote.ts
Normal file
67
models/baseModels/SalesQuote/SalesQuote.ts
Normal file
@ -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
models/baseModels/SalesQuoteItem/SalesQuoteItem.ts
Normal file
3
models/baseModels/SalesQuoteItem/SalesQuoteItem.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import { InvoiceItem } from '../InvoiceItem/InvoiceItem';
|
||||||
|
|
||||||
|
export class SalesQuoteItem extends InvoiceItem {}
|
@ -11,10 +11,18 @@ import {
|
|||||||
} from './baseModels/Account/types';
|
} from './baseModels/Account/types';
|
||||||
import { numberSeriesDefaultsMap } from './baseModels/Defaults/Defaults';
|
import { numberSeriesDefaultsMap } from './baseModels/Defaults/Defaults';
|
||||||
import { Invoice } from './baseModels/Invoice/Invoice';
|
import { Invoice } from './baseModels/Invoice/Invoice';
|
||||||
|
import { SalesQuote } from './baseModels/SalesQuote/SalesQuote';
|
||||||
import { StockMovement } from './inventory/StockMovement';
|
import { StockMovement } from './inventory/StockMovement';
|
||||||
import { StockTransfer } from './inventory/StockTransfer';
|
import { StockTransfer } from './inventory/StockTransfer';
|
||||||
import { InvoiceStatus, ModelNameEnum } from './types';
|
import { InvoiceStatus, ModelNameEnum } from './types';
|
||||||
|
|
||||||
|
export function getQuoteActions(
|
||||||
|
fyo: Fyo,
|
||||||
|
schemaName: ModelNameEnum.SalesQuote
|
||||||
|
): Action[] {
|
||||||
|
return [getMakeInvoiceAction(fyo, schemaName)];
|
||||||
|
}
|
||||||
|
|
||||||
export function getInvoiceActions(
|
export function getInvoiceActions(
|
||||||
fyo: Fyo,
|
fyo: Fyo,
|
||||||
schemaName: ModelNameEnum.SalesInvoice | ModelNameEnum.PurchaseInvoice
|
schemaName: ModelNameEnum.SalesInvoice | ModelNameEnum.PurchaseInvoice
|
||||||
@ -67,7 +75,10 @@ export function getMakeStockTransferAction(
|
|||||||
|
|
||||||
export function getMakeInvoiceAction(
|
export function getMakeInvoiceAction(
|
||||||
fyo: Fyo,
|
fyo: Fyo,
|
||||||
schemaName: ModelNameEnum.Shipment | ModelNameEnum.PurchaseReceipt
|
schemaName:
|
||||||
|
| ModelNameEnum.Shipment
|
||||||
|
| ModelNameEnum.PurchaseReceipt
|
||||||
|
| ModelNameEnum.SalesQuote
|
||||||
): Action {
|
): Action {
|
||||||
let label = fyo.t`Sales Invoice`;
|
let label = fyo.t`Sales Invoice`;
|
||||||
if (schemaName === ModelNameEnum.PurchaseReceipt) {
|
if (schemaName === ModelNameEnum.PurchaseReceipt) {
|
||||||
@ -77,9 +88,15 @@ export function getMakeInvoiceAction(
|
|||||||
return {
|
return {
|
||||||
label,
|
label,
|
||||||
group: fyo.t`Create`,
|
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) => {
|
action: async (doc: Doc) => {
|
||||||
const invoice = await (doc as StockTransfer).getInvoice();
|
const invoice = await (doc as SalesQuote | StockTransfer).getInvoice();
|
||||||
if (!invoice || !invoice.name) {
|
if (!invoice || !invoice.name) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,8 @@ import { PurchaseInvoice } from './baseModels/PurchaseInvoice/PurchaseInvoice';
|
|||||||
import { PurchaseInvoiceItem } from './baseModels/PurchaseInvoiceItem/PurchaseInvoiceItem';
|
import { PurchaseInvoiceItem } from './baseModels/PurchaseInvoiceItem/PurchaseInvoiceItem';
|
||||||
import { SalesInvoice } from './baseModels/SalesInvoice/SalesInvoice';
|
import { SalesInvoice } from './baseModels/SalesInvoice/SalesInvoice';
|
||||||
import { SalesInvoiceItem } from './baseModels/SalesInvoiceItem/SalesInvoiceItem';
|
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 { SetupWizard } from './baseModels/SetupWizard/SetupWizard';
|
||||||
import { Tax } from './baseModels/Tax/Tax';
|
import { Tax } from './baseModels/Tax/Tax';
|
||||||
import { TaxSummary } from './baseModels/TaxSummary/TaxSummary';
|
import { TaxSummary } from './baseModels/TaxSummary/TaxSummary';
|
||||||
@ -61,6 +63,8 @@ export const models = {
|
|||||||
PurchaseInvoiceItem,
|
PurchaseInvoiceItem,
|
||||||
SalesInvoice,
|
SalesInvoice,
|
||||||
SalesInvoiceItem,
|
SalesInvoiceItem,
|
||||||
|
SalesQuote,
|
||||||
|
SalesQuoteItem,
|
||||||
SerialNumber,
|
SerialNumber,
|
||||||
SetupWizard,
|
SetupWizard,
|
||||||
PrintTemplate,
|
PrintTemplate,
|
||||||
|
@ -27,6 +27,8 @@ export enum ModelNameEnum {
|
|||||||
PurchaseInvoiceItem = 'PurchaseInvoiceItem',
|
PurchaseInvoiceItem = 'PurchaseInvoiceItem',
|
||||||
SalesInvoice = 'SalesInvoice',
|
SalesInvoice = 'SalesInvoice',
|
||||||
SalesInvoiceItem = 'SalesInvoiceItem',
|
SalesInvoiceItem = 'SalesInvoiceItem',
|
||||||
|
SalesQuote = 'SalesQuote',
|
||||||
|
SalesQuoteItem = 'SalesQuoteItem',
|
||||||
SerialNumber = 'SerialNumber',
|
SerialNumber = 'SerialNumber',
|
||||||
SetupWizard = 'SetupWizard',
|
SetupWizard = 'SetupWizard',
|
||||||
Tax = 'Tax',
|
Tax = 'Tax',
|
||||||
|
@ -92,6 +92,14 @@
|
|||||||
"create": true,
|
"create": true,
|
||||||
"section": "Number Series"
|
"section": "Number Series"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "salesQuoteNumberSeries",
|
||||||
|
"label": "Sales Quote Number Series",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"target": "NumberSeries",
|
||||||
|
"create": true,
|
||||||
|
"section": "Number Series"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "salesInvoiceTerms",
|
"fieldname": "salesInvoiceTerms",
|
||||||
"label": "Sales Invoice Terms",
|
"label": "Sales Invoice Terms",
|
||||||
@ -116,6 +124,13 @@
|
|||||||
"fieldtype": "Text",
|
"fieldtype": "Text",
|
||||||
"section": "Terms"
|
"section": "Terms"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "salesQuotePrintTemplate",
|
||||||
|
"label": "Sales Quote Print Template",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"target": "PrintTemplate",
|
||||||
|
"section": "Print Templates"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "salesInvoicePrintTemplate",
|
"fieldname": "salesInvoicePrintTemplate",
|
||||||
"label": "Sales Invoice Print Template",
|
"label": "Sales Invoice Print Template",
|
||||||
|
@ -35,6 +35,10 @@
|
|||||||
"value": "SalesInvoice",
|
"value": "SalesInvoice",
|
||||||
"label": "Sales Invoice"
|
"label": "Sales Invoice"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"value": "SalesQuote",
|
||||||
|
"label": "Sales Quote"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"value": "PurchaseInvoice",
|
"value": "PurchaseInvoice",
|
||||||
"label": "Purchase Invoice"
|
"label": "Purchase Invoice"
|
||||||
|
@ -31,6 +31,14 @@
|
|||||||
"target": "Shipment",
|
"target": "Shipment",
|
||||||
"section": "References"
|
"section": "References"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"fieldname": "quote",
|
||||||
|
"label": "Quote Reference",
|
||||||
|
"fieldtype": "Link",
|
||||||
|
"target": "SalesQuote",
|
||||||
|
"section": "References",
|
||||||
|
"required": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"fieldname": "makeAutoStockTransfer",
|
"fieldname": "makeAutoStockTransfer",
|
||||||
"label": "Make Shipment On Submit",
|
"label": "Make Shipment On Submit",
|
||||||
|
46
schemas/app/SalesQuote.json
Normal file
46
schemas/app/SalesQuote.json
Normal file
@ -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
schemas/app/SalesQuoteItem.json
Normal file
5
schemas/app/SalesQuoteItem.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "SalesQuoteItem",
|
||||||
|
"label": "Sales Quote Item",
|
||||||
|
"extends": "InvoiceItem"
|
||||||
|
}
|
@ -25,6 +25,8 @@ import PurchaseInvoice from './app/PurchaseInvoice.json';
|
|||||||
import PurchaseInvoiceItem from './app/PurchaseInvoiceItem.json';
|
import PurchaseInvoiceItem from './app/PurchaseInvoiceItem.json';
|
||||||
import SalesInvoice from './app/SalesInvoice.json';
|
import SalesInvoice from './app/SalesInvoice.json';
|
||||||
import SalesInvoiceItem from './app/SalesInvoiceItem.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 SetupWizard from './app/SetupWizard.json';
|
||||||
import Tax from './app/Tax.json';
|
import Tax from './app/Tax.json';
|
||||||
import TaxDetail from './app/TaxDetail.json';
|
import TaxDetail from './app/TaxDetail.json';
|
||||||
@ -108,10 +110,12 @@ export const appSchemas: Schema[] | SchemaStub[] = [
|
|||||||
Invoice as Schema,
|
Invoice as Schema,
|
||||||
SalesInvoice as Schema,
|
SalesInvoice as Schema,
|
||||||
PurchaseInvoice as Schema,
|
PurchaseInvoice as Schema,
|
||||||
|
SalesQuote as Schema,
|
||||||
|
|
||||||
InvoiceItem as Schema,
|
InvoiceItem as Schema,
|
||||||
SalesInvoiceItem as SchemaStub,
|
SalesInvoiceItem as SchemaStub,
|
||||||
PurchaseInvoiceItem as SchemaStub,
|
PurchaseInvoiceItem as SchemaStub,
|
||||||
|
SalesQuoteItem as SchemaStub,
|
||||||
|
|
||||||
PriceList as Schema,
|
PriceList as Schema,
|
||||||
PriceListItem as SchemaStub,
|
PriceListItem as SchemaStub,
|
||||||
|
@ -150,6 +150,7 @@
|
|||||||
v-if="showDevMode"
|
v-if="showDevMode"
|
||||||
class="text-xs text-gray-500 select-none cursor-pointer"
|
class="text-xs text-gray-500 select-none cursor-pointer"
|
||||||
@click="showDevMode = false"
|
@click="showDevMode = false"
|
||||||
|
title="Open dev tools with Ctrl+Shift+I"
|
||||||
>
|
>
|
||||||
dev mode
|
dev mode
|
||||||
</p>
|
</p>
|
||||||
|
67
src/pages/TemplateBuilder/SetType.vue
Normal file
67
src/pages/TemplateBuilder/SetType.vue
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<template>
|
||||||
|
<div class="w-form">
|
||||||
|
<FormHeader :form-title="t`Set Print Size`" />
|
||||||
|
<hr />
|
||||||
|
<div class="p-4 w-full flex flex-col gap-4">
|
||||||
|
<p class="text-base text-gray-900">
|
||||||
|
{{ t`Select the template type.` }}
|
||||||
|
</p>
|
||||||
|
<Select
|
||||||
|
:df="df"
|
||||||
|
:value="type"
|
||||||
|
:border="true"
|
||||||
|
:show-label="true"
|
||||||
|
@change="typeChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="flex border-t p-4">
|
||||||
|
<Button class="ml-auto" type="primary" @click="done">{{
|
||||||
|
t`Done`
|
||||||
|
}}</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts">
|
||||||
|
import { PrintTemplate } from 'models/baseModels/PrintTemplate';
|
||||||
|
import { OptionField } from 'schemas/types';
|
||||||
|
import Button from 'src/components/Button.vue';
|
||||||
|
import Select from 'src/components/Controls/Select.vue';
|
||||||
|
import FormHeader from 'src/components/FormHeader.vue';
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: { FormHeader, Select, Button },
|
||||||
|
props: { doc: { type: PrintTemplate, required: true } },
|
||||||
|
emits: ['done'],
|
||||||
|
data() {
|
||||||
|
return { type: 'SalesInvoice' };
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
df(): OptionField {
|
||||||
|
const options = PrintTemplate.lists.type(this.doc);
|
||||||
|
return {
|
||||||
|
...fyo.getField('PrintTemplate', 'type'),
|
||||||
|
options,
|
||||||
|
fieldtype: 'Select',
|
||||||
|
default: options[0].value,
|
||||||
|
} as OptionField;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.type = this.doc.type ?? 'SalesInvoice';
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
typeChange(v: string) {
|
||||||
|
if (this.type === v) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.type = v;
|
||||||
|
},
|
||||||
|
async done() {
|
||||||
|
await this.doc.set('type', this.type);
|
||||||
|
this.$emit('done');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
@ -213,6 +213,13 @@
|
|||||||
>
|
>
|
||||||
<SetPrintSize :doc="doc" @done="showSizeModal = !showSizeModal" />
|
<SetPrintSize :doc="doc" @done="showSizeModal = !showSizeModal" />
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
v-if="doc"
|
||||||
|
:open-modal="showTypeModal"
|
||||||
|
@closemodal="showTypeModal = !showTypeModal"
|
||||||
|
>
|
||||||
|
<SetType :doc="doc" @done="showTypeModal = !showTypeModal" />
|
||||||
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -256,6 +263,7 @@ import { getMapFromList } from 'utils/index';
|
|||||||
import { computed, defineComponent, inject, ref } from 'vue';
|
import { computed, defineComponent, inject, ref } from 'vue';
|
||||||
import PrintContainer from './PrintContainer.vue';
|
import PrintContainer from './PrintContainer.vue';
|
||||||
import SetPrintSize from './SetPrintSize.vue';
|
import SetPrintSize from './SetPrintSize.vue';
|
||||||
|
import SetType from './SetType.vue';
|
||||||
import TemplateBuilderHint from './TemplateBuilderHint.vue';
|
import TemplateBuilderHint from './TemplateBuilderHint.vue';
|
||||||
import TemplateEditor from './TemplateEditor.vue';
|
import TemplateEditor from './TemplateEditor.vue';
|
||||||
|
|
||||||
@ -273,6 +281,7 @@ export default defineComponent({
|
|||||||
Link,
|
Link,
|
||||||
Modal,
|
Modal,
|
||||||
SetPrintSize,
|
SetPrintSize,
|
||||||
|
SetType,
|
||||||
},
|
},
|
||||||
provide() {
|
provide() {
|
||||||
return { doc: computed(() => this.doc) };
|
return { doc: computed(() => this.doc) };
|
||||||
@ -303,6 +312,7 @@ export default defineComponent({
|
|||||||
scale: 0.6,
|
scale: 0.6,
|
||||||
panelWidth: 22 /** rem */ * 16 /** px */,
|
panelWidth: 22 /** rem */ * 16 /** px */,
|
||||||
templateChanged: false,
|
templateChanged: false,
|
||||||
|
showTypeModal: false,
|
||||||
showSizeModal: false,
|
showSizeModal: false,
|
||||||
preEditMode: {
|
preEditMode: {
|
||||||
scale: 0.6,
|
scale: 0.6,
|
||||||
@ -315,6 +325,7 @@ export default defineComponent({
|
|||||||
hints?: PrintTemplateHint;
|
hints?: PrintTemplateHint;
|
||||||
values: null | PrintValues;
|
values: null | PrintValues;
|
||||||
displayDoc: PrintTemplate | null;
|
displayDoc: PrintTemplate | null;
|
||||||
|
showTypeModal: boolean;
|
||||||
showSizeModal: boolean;
|
showSizeModal: boolean;
|
||||||
scale: number;
|
scale: number;
|
||||||
panelWidth: number;
|
panelWidth: number;
|
||||||
@ -367,6 +378,14 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.doc.isCustom && !this.showTypeModal) {
|
||||||
|
actions.push({
|
||||||
|
label: this.t`Set Template Type`,
|
||||||
|
group: this.t`Action`,
|
||||||
|
action: () => (this.showTypeModal = true),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (this.doc.isCustom && !this.showSizeModal) {
|
if (this.doc.isCustom && !this.showSizeModal) {
|
||||||
actions.push({
|
actions.push({
|
||||||
label: this.t`Set Print Size`,
|
label: this.t`Set Print Size`,
|
||||||
|
@ -37,8 +37,6 @@ export async function getPrintTemplatePropValues(
|
|||||||
const fyo = doc.fyo;
|
const fyo = doc.fyo;
|
||||||
const values: PrintValues = { doc: {}, print: {} };
|
const values: PrintValues = { doc: {}, print: {} };
|
||||||
values.doc = await getPrintTemplateDocValues(doc);
|
values.doc = await getPrintTemplateDocValues(doc);
|
||||||
(values.doc as PrintTemplateData).entryType = doc.schema.name;
|
|
||||||
(values.doc as PrintTemplateData).entryLabel = doc.schema.label;
|
|
||||||
|
|
||||||
const printSettings = await fyo.doc.getDoc(ModelNameEnum.PrintSettings);
|
const printSettings = await fyo.doc.getDoc(ModelNameEnum.PrintSettings);
|
||||||
const printValues = await getPrintTemplateDocValues(
|
const printValues = await getPrintTemplateDocValues(
|
||||||
@ -72,8 +70,6 @@ export function getPrintTemplatePropHints(schemaName: string, fyo: Fyo) {
|
|||||||
const hints: PrintTemplateHint = {};
|
const hints: PrintTemplateHint = {};
|
||||||
const schema = fyo.schemaMap[schemaName]!;
|
const schema = fyo.schemaMap[schemaName]!;
|
||||||
hints.doc = getPrintTemplateDocHints(schema, fyo);
|
hints.doc = getPrintTemplateDocHints(schema, fyo);
|
||||||
hints.doc.entryType = fyo.t`Entry Type`;
|
|
||||||
hints.doc.entryLabel = fyo.t`Entry Label`;
|
|
||||||
|
|
||||||
const printSettingsHints = getPrintTemplateDocHints(
|
const printSettingsHints = getPrintTemplateDocHints(
|
||||||
fyo.schemaMap[ModelNameEnum.PrintSettings]!,
|
fyo.schemaMap[ModelNameEnum.PrintSettings]!,
|
||||||
@ -159,6 +155,10 @@ function getPrintTemplateDocHints(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hints.submitted = fyo.t`Submitted`;
|
||||||
|
hints.entryType = fyo.t`Entry Type`;
|
||||||
|
hints.entryLabel = fyo.t`Entry Label`;
|
||||||
|
|
||||||
if (Object.keys(links).length) {
|
if (Object.keys(links).length) {
|
||||||
hints.links = links;
|
hints.links = links;
|
||||||
}
|
}
|
||||||
@ -204,6 +204,10 @@ async function getPrintTemplateDocValues(doc: Doc, fieldnames?: string[]) {
|
|||||||
values[fieldname] = table;
|
values[fieldname] = table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
values.submitted = doc.submitted;
|
||||||
|
values.entryType = doc.schema.name;
|
||||||
|
values.entryLabel = doc.schema.label;
|
||||||
|
|
||||||
// Set Formatted Doc Link Data
|
// Set Formatted Doc Link Data
|
||||||
await doc.loadLinks();
|
await doc.loadLinks();
|
||||||
const links: PrintTemplateData = {};
|
const links: PrintTemplateData = {};
|
||||||
@ -347,6 +351,7 @@ function getNameAndTypeFromTemplateFile(
|
|||||||
* If the SchemaName is absent then it is assumed
|
* If the SchemaName is absent then it is assumed
|
||||||
* that the SchemaName is:
|
* that the SchemaName is:
|
||||||
* - SalesInvoice
|
* - SalesInvoice
|
||||||
|
* - SalesQuote
|
||||||
* - PurchaseInvoice
|
* - PurchaseInvoice
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -359,12 +364,14 @@ function getNameAndTypeFromTemplateFile(
|
|||||||
return [{ name: `${name} - ${label}`, type: schemaName }];
|
return [{ name: `${name} - ${label}`, type: schemaName }];
|
||||||
}
|
}
|
||||||
|
|
||||||
return [ModelNameEnum.SalesInvoice, ModelNameEnum.PurchaseInvoice].map(
|
return [
|
||||||
(schemaName) => {
|
ModelNameEnum.SalesInvoice,
|
||||||
|
ModelNameEnum.SalesQuote,
|
||||||
|
ModelNameEnum.PurchaseInvoice,
|
||||||
|
].map((schemaName) => {
|
||||||
const label = fyo.schemaMap[schemaName]?.label ?? schemaName;
|
const label = fyo.schemaMap[schemaName]?.label ?? schemaName;
|
||||||
return { name: `${name} - ${label}`, type: schemaName };
|
return { name: `${name} - ${label}`, type: schemaName };
|
||||||
}
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const baseTemplate = `<main class="h-full w-full bg-white">
|
export const baseTemplate = `<main class="h-full w-full bg-white">
|
||||||
|
@ -169,6 +169,12 @@ function getCompleteSidebar(): SidebarConfig {
|
|||||||
icon: 'sales',
|
icon: 'sales',
|
||||||
route: '/list/SalesInvoice',
|
route: '/list/SalesInvoice',
|
||||||
items: [
|
items: [
|
||||||
|
{
|
||||||
|
label: t`Sales Quotes`,
|
||||||
|
name: 'sales-quotes',
|
||||||
|
route: '/list/SalesQuote',
|
||||||
|
schemaName: 'SalesQuote',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: t`Sales Invoices`,
|
label: t`Sales Invoices`,
|
||||||
name: 'sales-invoices',
|
name: 'sales-invoices',
|
||||||
|
@ -52,8 +52,8 @@ Accounts,Comptes,
|
|||||||
"Accounts Payable","Comptes créditeurs",
|
"Accounts Payable","Comptes créditeurs",
|
||||||
"Accounts Receivable","Comptes débiteurs",
|
"Accounts Receivable","Comptes débiteurs",
|
||||||
"Accumulated Depreciation","Amortissement cumulé",
|
"Accumulated Depreciation","Amortissement cumulé",
|
||||||
Action,,
|
Action,Action,
|
||||||
Active,,
|
Active,Actif,
|
||||||
"Add Account","Ajouter un compte",
|
"Add Account","Ajouter un compte",
|
||||||
"Add Customers","Ajouter des clients",
|
"Add Customers","Ajouter des clients",
|
||||||
"Add Group","Ajouter un groupe",
|
"Add Group","Ajouter un groupe",
|
||||||
@ -689,6 +689,8 @@ Quarterly,Trimestriel,
|
|||||||
Quarters,Trimestres,
|
Quarters,Trimestres,
|
||||||
"Quick Search",,
|
"Quick Search",,
|
||||||
"Quick edit error: ${0} entry has no name.",,
|
"Quick edit error: ${0} entry has no name.",,
|
||||||
|
"Quote","Devis",
|
||||||
|
"Quote Reference","Référence du devis",
|
||||||
Rate,Tarif,
|
Rate,Tarif,
|
||||||
"Rate (${0}) cannot be less zero.","Le Tarif (${0}) ne peut pas être inférieur à zéro.",
|
"Rate (${0}) cannot be less zero.","Le Tarif (${0}) ne peut pas être inférieur à zéro.",
|
||||||
"Rate (${0}) has to be greater than zero",,
|
"Rate (${0}) has to be greater than zero",,
|
||||||
@ -739,6 +741,9 @@ Sales,Ventes,
|
|||||||
"Sales Acc.",,
|
"Sales Acc.",,
|
||||||
"Sales Expenses","Frais de vente",
|
"Sales Expenses","Frais de vente",
|
||||||
"Sales Invoice","Facture de vente",
|
"Sales Invoice","Facture de vente",
|
||||||
|
"Sales Quote","Devis de vente",
|
||||||
|
"Sales Quote Number Series",,
|
||||||
|
"Sales Quote Print Template",,
|
||||||
"Sales Invoice Item","Facture de vente d'article",
|
"Sales Invoice Item","Facture de vente d'article",
|
||||||
"Sales Invoice Number Series",,
|
"Sales Invoice Number Series",,
|
||||||
"Sales Invoice Print Template",,
|
"Sales Invoice Print Template",,
|
||||||
@ -792,7 +797,8 @@ September,,
|
|||||||
Service,,
|
Service,,
|
||||||
"Set Discount Amount","Définir le montant de la réduction",
|
"Set Discount Amount","Définir le montant de la réduction",
|
||||||
"Set Period",,
|
"Set Period",,
|
||||||
"Set Print Size",,
|
"Set Print Size","Définir le format de page",
|
||||||
|
"Set Template Type","Définir le type de modèle",
|
||||||
"Set Up",Configurer,
|
"Set Up",Configurer,
|
||||||
"Set Up Your Workspace","Configurez votre espace de travail",
|
"Set Up Your Workspace","Configurez votre espace de travail",
|
||||||
"Set a Template value to see the Print Template",,
|
"Set a Template value to see the Print Template",,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user