2
0
mirror of https://github.com/frappe/books.git synced 2025-01-03 07:12:21 +00:00

refactor: pos shift

This commit is contained in:
akshayitzme 2024-12-24 22:17:40 +05:30
parent 1ed99d1b44
commit 5061a0ce22
16 changed files with 184 additions and 122 deletions

View File

@ -11,7 +11,8 @@ import type { PrintSettings } from 'models/baseModels/PrintSettings/PrintSetting
import type { InventorySettings } from 'models/inventory/InventorySettings';
import type { Misc } from 'models/baseModels/Misc';
import type { POSSettings } from 'models/inventory/Point of Sale/POSSettings';
import type { POSShift } from 'models/inventory/Point of Sale/POSShift';
import type { POSOpeningShift } from 'models/inventory/Point of Sale/POSOpeningShift';
import type { POSClosingShift } from 'models/inventory/Point of Sale/POSClosingShift';
/**
* The functions below are used for dynamic evaluation
@ -57,7 +58,8 @@ export interface SinglesMap {
AccountingSettings?: AccountingSettings;
InventorySettings?: InventorySettings;
POSSettings?: POSSettings;
POSShift?: POSShift;
POSOpeningShift?: POSOpeningShift;
POSClosingShift?: POSClosingShift;
PrintSettings?: PrintSettings;
Defaults?: Defaults;
Misc?: Misc;

View File

@ -48,7 +48,8 @@ import { ClosingCash } from './inventory/Point of Sale/ClosingCash';
import { OpeningAmounts } from './inventory/Point of Sale/OpeningAmounts';
import { OpeningCash } from './inventory/Point of Sale/OpeningCash';
import { POSSettings } from './inventory/Point of Sale/POSSettings';
import { POSShift } from './inventory/Point of Sale/POSShift';
import { POSOpeningShift } from './inventory/Point of Sale/POSOpeningShift';
import { POSClosingShift } from './inventory/Point of Sale/POSClosingShift';
export const models = {
Account,
@ -102,7 +103,8 @@ export const models = {
OpeningAmounts,
OpeningCash,
POSSettings,
POSShift,
POSOpeningShift,
POSClosingShift,
} as ModelMap;
export async function getRegionalModels(

View File

@ -46,7 +46,7 @@ export class InventorySettings extends Doc {
return !!this.enableStockReturns;
},
enablePointOfSale: () => {
return !!this.fyo.singles.POSShift?.isShiftOpen;
return !!this.fyo.singles.POSSettings?.isShiftOpen;
},
};
}

View File

@ -0,0 +1,33 @@
import { ListViewSettings } from 'fyo/model/types';
import { ClosingAmounts } from './ClosingAmounts';
import { ClosingCash } from './ClosingCash';
import { Doc } from 'fyo/model/doc';
export class POSClosingShift extends Doc {
closingAmounts?: ClosingAmounts[];
closingCash?: ClosingCash[];
closingDate?: Date;
get closingCashAmount() {
if (!this.closingCash) {
return this.fyo.pesa(0);
}
let closingAmount = this.fyo.pesa(0);
this.closingCash.map((row: ClosingCash) => {
const denomination = row.denomination ?? this.fyo.pesa(0);
const count = row.count ?? 0;
const amount = denomination.mul(count);
closingAmount = closingAmount.add(amount);
});
return closingAmount;
}
static getListViewSettings(): ListViewSettings {
return {
columns: ['name', 'closingDate'],
};
}
}

View File

@ -1,14 +1,9 @@
import { ClosingAmounts } from './ClosingAmounts';
import { ClosingCash } from './ClosingCash';
import { Doc } from 'fyo/model/doc';
import { OpeningAmounts } from './OpeningAmounts';
import { OpeningCash } from './OpeningCash';
import { ListViewSettings } from 'fyo/model/types';
export class POSShift extends Doc {
closingAmounts?: ClosingAmounts[];
closingCash?: ClosingCash[];
closingDate?: Date;
isShiftOpen?: boolean;
export class POSOpeningShift extends Doc {
openingAmounts?: OpeningAmounts[];
openingCash?: OpeningCash[];
openingDate?: Date;
@ -30,23 +25,6 @@ export class POSShift extends Doc {
return openingAmount;
}
get closingCashAmount() {
if (!this.closingCash) {
return this.fyo.pesa(0);
}
let closingAmount = this.fyo.pesa(0);
this.closingCash.map((row: ClosingCash) => {
const denomination = row.denomination ?? this.fyo.pesa(0);
const count = row.count ?? 0;
const amount = denomination.mul(count);
closingAmount = closingAmount.add(amount);
});
return closingAmount;
}
get openingTransferAmount() {
if (!this.openingAmounts) {
return this.fyo.pesa(0);
@ -58,4 +36,10 @@ export class POSShift extends Doc {
return transferAmountRow.amount ?? this.fyo.pesa(0);
}
static getListViewSettings(): ListViewSettings {
return {
columns: ['name', 'openingDate'],
};
}
}

View File

@ -6,6 +6,7 @@ import {
} from 'models/baseModels/Account/types';
export class POSSettings extends Doc {
isShiftOpen?: boolean;
inventory?: string;
cashAccount?: string;
writeOffAccount?: string;

View File

@ -59,7 +59,12 @@ export enum ModelNameEnum {
CustomForm = 'CustomForm',
CustomField = 'CustomField',
POSSettings = 'POSSettings',
POSShift = 'POSShift'
POSOpeningShift = 'POSOpeningShift',
POSClosingShift = 'POSClosingShift',
ERPNextSyncSettings= 'ERPNextSyncSettings',
ERPNextSyncQueue = 'ERPNextSyncQueue',
FetchFromERPNextQueue = 'FetchFromERPNextQueue',
}
export type ModelName = keyof typeof ModelNameEnum;

View File

@ -0,0 +1,24 @@
{
"name": "POSClosingShift",
"label": "POS Closing Shift",
"naming": "random",
"fields": [
{
"fieldname": "closingDate",
"label": "Closing Date",
"fieldtype": "Datetime"
},
{
"fieldname": "closingCash",
"fieldtype": "Table",
"label": "Closing Cash",
"target": "ClosingCash"
},
{
"fieldname": "closingAmounts",
"fieldtype": "Table",
"label": "Closing Amounts",
"target": "ClosingAmounts"
}
]
}

View File

@ -0,0 +1,24 @@
{
"name": "POSOpeningShift",
"label": "POS Opening Shift",
"naming": "random",
"fields": [
{
"fieldname": "openingDate",
"label": "Opening Date",
"fieldtype": "Datetime"
},
{
"fieldname": "openingCash",
"fieldtype": "Table",
"label": "Opening Cash",
"target": "OpeningCash"
},
{
"fieldname": "openingAmounts",
"fieldtype": "Table",
"label": "Opening Amounts",
"target": "OpeningAmounts"
}
]
}

View File

@ -4,6 +4,13 @@
"isSingle": true,
"isChild": false,
"fields": [
{
"fieldname": "isShiftOpen",
"label": "Is POS Shift Open",
"fieldtype": "Check",
"default": false,
"hidden": false
},
{
"fieldname": "inventory",
"label": "Inventory",

View File

@ -1,43 +0,0 @@
{
"name": "POSShift",
"isSingle": true,
"isChild": false,
"fields": [
{
"fieldname": "isShiftOpen",
"label": "Is POS Shift Open",
"fieldtype": "Check",
"default": false
},
{
"fieldname": "openingDate",
"label": "Opening Date",
"fieldtype": "Datetime"
},
{
"fieldname": "closingDate",
"label": "Closing Date",
"fieldtype": "Datetime"
},
{
"fieldname": "openingCash",
"fieldtype": "Table",
"target": "OpeningCash"
},
{
"fieldname": "closingCash",
"fieldtype": "Table",
"target": "ClosingCash"
},
{
"fieldname": "openingAmounts",
"fieldtype": "Table",
"target": "OpeningAmounts"
},
{
"fieldname": "closingAmounts",
"fieldtype": "Table",
"target": "ClosingAmounts"
}
]
}

View File

@ -70,7 +70,8 @@ import DefaultCashDenominations from './app/inventory/Point of Sale/DefaultCashD
import OpeningAmounts from './app/inventory/Point of Sale/OpeningAmounts.json';
import OpeningCash from './app/inventory/Point of Sale/OpeningCash.json';
import POSSettings from './app/inventory/Point of Sale/POSSettings.json';
import POSShift from './app/inventory/Point of Sale/POSShift.json';
import POSOpeningShift from './app/inventory/Point of Sale/POSOpeningShift.json';
import POSClosingShift from './app/inventory/Point of Sale/POSClosingShift.json';
import POSShiftAmounts from './app/inventory/Point of Sale/POSShiftAmounts.json';
import { Schema, SchemaStub } from './types';
@ -170,6 +171,7 @@ export const appSchemas: Schema[] | SchemaStub[] = [
OpeningAmounts as Schema,
OpeningCash as Schema,
POSSettings as Schema,
POSShift as Schema,
POSOpeningShift as Schema,
POSClosingShift as Schema,
POSShiftAmounts as Schema,
];

View File

@ -13,9 +13,8 @@
:df="getField('closingCash')"
:show-header="true"
:border="true"
:value="posShiftDoc?.closingCash ?? []"
:value="posClosingShiftDoc?.closingCash ?? []"
:read-only="false"
@row-change="handleChange"
/>
<h2 class="mt-6 mb-2 text-lg dark:text-gray-100 font-medium">
@ -27,9 +26,8 @@
:df="getField('closingAmounts')"
:show-header="true"
:border="true"
:value="posShiftDoc?.closingAmounts"
:value="posClosingShiftDoc?.closingAmounts"
:read-only="true"
@row-change="handleChange"
/>
<div class="mt-4 grid grid-cols-2 gap-4 items-end">
@ -65,7 +63,7 @@ import Table from 'src/components/Controls/Table.vue';
import { ModelNameEnum } from 'models/types';
import { Money } from 'pesa';
import { OpeningAmounts } from 'models/inventory/Point of Sale/OpeningAmounts';
import { POSShift } from 'models/inventory/Point of Sale/POSShift';
import { POSOpeningShift } from 'models/inventory/Point of Sale/POSOpeningShift';
import { computed } from 'vue';
import { defineComponent } from 'vue';
import { fyo } from 'src/initFyo';
@ -74,14 +72,16 @@ import { t } from 'fyo';
import {
validateClosingAmounts,
transferPOSCashAndWriteOff,
getPOSOpeningShiftDoc,
} from 'src/utils/pos';
import { POSClosingShift } from 'models/inventory/Point of Sale/POSClosingShift';
export default defineComponent({
name: 'ClosePOSShiftModal',
components: { Button, Modal, Table },
provide() {
return {
doc: computed(() => this.posShiftDoc),
doc: computed(() => this.posClosingShiftDoc),
};
},
props: {
@ -95,7 +95,8 @@ export default defineComponent({
return {
isValuesSeeded: false,
posShiftDoc: undefined as POSShift | undefined,
posOpeningShiftDoc: undefined as POSOpeningShift | undefined,
posClosingShiftDoc: undefined as POSClosingShift | undefined,
transactedAmount: {} as Record<string, Money> | undefined,
};
},
@ -108,16 +109,22 @@ export default defineComponent({
},
},
async activated() {
this.posShiftDoc = fyo.singles[ModelNameEnum.POSShift];
this.posClosingShiftDoc = fyo.doc.getNewDoc(
ModelNameEnum.POSClosingShift
) as POSClosingShift;
await this.seedValues();
await this.setTransactedAmount();
},
async updated() {
this.posOpeningShiftDoc = await getPOSOpeningShiftDoc(fyo);
await this.seedValues();
},
methods: {
async setTransactedAmount() {
if (!fyo.singles.POSShift?.openingDate) {
return;
}
const fromDate = fyo.singles.POSShift?.openingDate;
const fromDate = this.posOpeningShiftDoc?.openingDate as Date;
this.transactedAmount = await fyo.db.getPOSTransactedAmount(
fromDate,
new Date(),
@ -125,29 +132,28 @@ export default defineComponent({
);
},
seedClosingCash() {
if (!this.posShiftDoc) {
if (!this.posClosingShiftDoc) {
return;
}
this.posShiftDoc.closingCash = [];
this.posClosingShiftDoc.closingCash = [];
this.posShiftDoc?.openingCash?.map(async (row) => {
await this.posShiftDoc?.append('closingCash', {
this.posOpeningShiftDoc?.openingCash?.map(async (row) => {
await this.posClosingShiftDoc?.append('closingCash', {
count: row.count,
denomination: row.denomination as Money,
});
});
},
async seedClosingAmounts() {
if (!this.posShiftDoc) {
if (!this.posClosingShiftDoc || !this.posOpeningShiftDoc) {
return;
}
this.posShiftDoc.closingAmounts = [];
await this.posShiftDoc.sync();
this.posClosingShiftDoc.closingAmounts = [];
const openingAmounts = this.posShiftDoc
.openingAmounts as OpeningAmounts[];
const openingAmounts = this.posOpeningShiftDoc
?.openingAmounts as OpeningAmounts[];
for (const row of openingAmounts) {
if (!row.paymentMethod) {
@ -158,13 +164,13 @@ export default defineComponent({
if (row.paymentMethod === 'Cash') {
expectedAmount = expectedAmount.add(
this.posShiftDoc.openingCashAmount as Money
this.posOpeningShiftDoc?.openingCashAmount as Money
);
}
if (row.paymentMethod === 'Transfer') {
expectedAmount = expectedAmount.add(
this.posShiftDoc.openingTransferAmount as Money
this.posOpeningShiftDoc?.openingTransferAmount as Money
);
}
@ -174,14 +180,13 @@ export default defineComponent({
);
}
await this.posShiftDoc.append('closingAmounts', {
await this.posClosingShiftDoc.append('closingAmounts', {
paymentMethod: row.paymentMethod,
openingAmount: row.amount,
closingAmount: fyo.pesa(0),
expectedAmount: expectedAmount,
differenceAmount: fyo.pesa(0),
});
await this.posShiftDoc.sync();
}
},
async seedValues() {
@ -191,19 +196,20 @@ export default defineComponent({
this.isValuesSeeded = true;
},
getField(fieldname: string) {
return fyo.getField(ModelNameEnum.POSShift, fieldname);
},
async handleChange() {
await this.posShiftDoc?.sync();
return fyo.getField(ModelNameEnum.POSClosingShift, fieldname);
},
async handleSubmit() {
try {
validateClosingAmounts(this.posShiftDoc as POSShift);
await this.posShiftDoc?.set('isShiftOpen', false);
await this.posShiftDoc?.set('closingDate', new Date());
await this.posShiftDoc?.sync();
await transferPOSCashAndWriteOff(fyo, this.posShiftDoc as POSShift);
validateClosingAmounts(this.posClosingShiftDoc as POSClosingShift);
await this.posClosingShiftDoc?.set('isShiftOpen', false);
await this.posClosingShiftDoc?.set('closingDate', new Date());
await this.posClosingShiftDoc?.sync();
await transferPOSCashAndWriteOff(
fyo,
this.posClosingShiftDoc as POSClosingShift
);
await this.fyo.singles.POSSettings?.setAndSync('isShiftOpen', false);
this.$emit('toggleModal', 'ShiftClose');
} catch (error) {
return showToast({

View File

@ -71,13 +71,14 @@ import Table from 'src/components/Controls/Table.vue';
import { AccountTypeEnum } from 'models/baseModels/Account/types';
import { ModelNameEnum } from 'models/types';
import { Money } from 'pesa';
import { POSShift } from 'models/inventory/Point of Sale/POSShift';
import { POSOpeningShift } from 'models/inventory/Point of Sale/POSOpeningShift';
import { computed } from 'vue';
import { defineComponent } from 'vue';
import { fyo } from 'src/initFyo';
import { showToast } from 'src/utils/interactive';
import { t } from 'fyo';
import { ValidationError } from 'fyo/utils/errors';
import { getPOSOpeningShiftDoc } from 'src/utils/pos';
export default defineComponent({
name: 'OpenPOSShift',
@ -90,7 +91,7 @@ export default defineComponent({
emits: ['toggleModal'],
data() {
return {
posShiftDoc: undefined as POSShift | undefined,
posShiftDoc: undefined as POSOpeningShift | undefined,
isValuesSeeded: false,
};
@ -108,7 +109,7 @@ export default defineComponent({
},
async mounted() {
this.isValuesSeeded = false;
this.posShiftDoc = fyo.singles[ModelNameEnum.POSShift];
this.posShiftDoc = await getPOSOpeningShiftDoc(fyo);
await this.seedDefaults();
this.isValuesSeeded = true;
@ -120,8 +121,6 @@ export default defineComponent({
}
this.posShiftDoc.openingCash = [];
await this.posShiftDoc.sync();
const denominations = this.getDefaultCashDenominations;
if (!denominations) {
@ -133,8 +132,6 @@ export default defineComponent({
denomination: row.denomination,
count: 0,
});
await this.posShiftDoc.sync();
}
},
async seedPaymentMethods() {
@ -143,7 +140,6 @@ export default defineComponent({
}
this.posShiftDoc.openingAmounts = [];
await this.posShiftDoc.sync();
await this.posShiftDoc.set('openingAmounts', [
{
@ -155,7 +151,6 @@ export default defineComponent({
amount: fyo.pesa(0),
},
]);
await this.posShiftDoc.sync();
},
async seedDefaults() {
if (!!this.posShiftDoc?.isShiftOpen) {
@ -166,7 +161,7 @@ export default defineComponent({
await this.seedPaymentMethods();
},
getField(fieldname: string) {
return this.fyo.getField(ModelNameEnum.POSShift, fieldname);
return this.fyo.getField(ModelNameEnum.POSOpeningShift, fieldname);
},
setOpeningCashAmount() {
if (!this.posShiftDoc?.openingAmounts) {
@ -179,8 +174,7 @@ export default defineComponent({
}
});
},
async handleChange() {
await this.posShiftDoc?.sync();
handleChange() {
this.setOpeningCashAmount();
},
async handleSubmit() {
@ -197,6 +191,7 @@ export default defineComponent({
});
await this.posShiftDoc?.sync();
await this.fyo.singles.POSSettings?.setAndSync('isShiftOpen', true);
if (!this.posShiftDoc?.openingCashAmount.isZero()) {
const jvDoc = fyo.doc.getNewDoc(ModelNameEnum.JournalEntry, {

View File

@ -219,7 +219,7 @@ export default defineComponent({
isDiscountingEnabled(): boolean {
return !!fyo.singles.AccountingSettings?.enableDiscounting;
},
isPosShiftOpen: () => !!fyo.singles.POSShift?.isShiftOpen,
isPosShiftOpen: () => !!fyo.singles.POSSettings?.isShiftOpen,
disablePayButton(): boolean {
if (!this.sinvDoc.items?.length || !this.sinvDoc.party) {
return true;

View File

@ -4,13 +4,33 @@ import { AccountTypeEnum } from 'models/baseModels/Account/types';
import { Item } from 'models/baseModels/Item/Item';
import { SalesInvoice } from 'models/baseModels/SalesInvoice/SalesInvoice';
import { SalesInvoiceItem } from 'models/baseModels/SalesInvoiceItem/SalesInvoiceItem';
import { POSShift } from 'models/inventory/Point of Sale/POSShift';
import { POSOpeningShift } from 'models/inventory/Point of Sale/POSOpeningShift';
import { ModelNameEnum } from 'models/types';
import { Money } from 'pesa';
import { ItemQtyMap, ItemSerialNumbers } from 'src/components/POS/types';
import { fyo } from 'src/initFyo';
import { safeParseFloat } from 'utils/index';
import { showToast } from './interactive';
import { POSClosingShift } from 'models/inventory/Point of Sale/POSClosingShift';
export async function getPOSOpeningShiftDoc(
fyo: Fyo
): Promise<POSOpeningShift> {
const existingShiftDoc = await fyo.db.getAll(ModelNameEnum.POSOpeningShift, {
limit: 1,
orderBy: 'created',
fields: ['name'],
});
if (!fyo.singles.POSSettings?.isShiftOpen || !existingShiftDoc) {
return fyo.doc.getNewDoc(ModelNameEnum.POSOpeningShift) as POSOpeningShift;
}
return (await fyo.doc.getDoc(
ModelNameEnum.POSOpeningShift,
existingShiftDoc[0].name as string
)) as POSOpeningShift;
}
export function getTotalQuantity(items: SalesInvoiceItem[]): number {
let totalQuantity = safeParseFloat(0);
@ -156,7 +176,7 @@ export function getTotalTaxedAmount(sinvDoc: SalesInvoice): Money {
return totalTaxedAmount;
}
export function validateClosingAmounts(posShiftDoc: POSShift) {
export function validateClosingAmounts(posShiftDoc: POSClosingShift) {
try {
if (!posShiftDoc) {
throw new ValidationError(
@ -176,7 +196,7 @@ export function validateClosingAmounts(posShiftDoc: POSShift) {
export async function transferPOSCashAndWriteOff(
fyo: Fyo,
posShiftDoc: POSShift
posShiftDoc: POSClosingShift
) {
const expectedCashAmount = posShiftDoc.closingAmounts?.find(
(row) => row.paymentMethod === 'Cash'