WIP: Allocate landed cost.

This commit is contained in:
a.bouhuolia
2021-07-23 01:32:10 +02:00
parent 76c6cb3699
commit 70aea9bf2d
5 changed files with 91 additions and 54 deletions

View File

@@ -5,7 +5,6 @@ import { ServiceError } from 'exceptions';
import AllocateLandedCostService from 'services/Purchases/LandedCost';
import LandedCostListing from 'services/Purchases/LandedCost/LandedCostListing';
import BaseController from '../BaseController';
import { ResultSetDependencies } from 'mathjs';
@Service()
export default class BillAllocateLandedCost extends BaseController {
@@ -221,8 +220,8 @@ export default class BillAllocateLandedCost extends BaseController {
errors: [
{
type: 'BILL_NOT_FOUND',
code: 400,
message: 'The give bill id not found.',
code: 100,
},
],
});
@@ -232,8 +231,8 @@ export default class BillAllocateLandedCost extends BaseController {
errors: [
{
type: 'LANDED_COST_TRANSACTION_NOT_FOUND',
code: 200,
message: 'The given landed cost transaction id not found.',
code: 200,
},
],
});
@@ -243,8 +242,8 @@ export default class BillAllocateLandedCost extends BaseController {
errors: [
{
type: 'LANDED_COST_ENTRY_NOT_FOUND',
code: 300,
message: 'The given landed cost tranasction entry id not found.',
code: 300,
},
],
});
@@ -252,7 +251,10 @@ export default class BillAllocateLandedCost extends BaseController {
if (error.errorType === 'COST_AMOUNT_BIGGER_THAN_UNALLOCATED_AMOUNT') {
return res.status(400).send({
errors: [
{ type: 'COST_AMOUNT_BIGGER_THAN_UNALLOCATED_AMOUNT', code: 300 },
{
type: 'COST_AMOUNT_BIGGER_THAN_UNALLOCATED_AMOUNT',
code: 400,
},
],
});
}
@@ -261,8 +263,8 @@ export default class BillAllocateLandedCost extends BaseController {
errors: [
{
type: 'LANDED_COST_ITEMS_IDS_NOT_FOUND',
code: 200,
message: 'The given entries ids of purchase invoice not found.',
code: 500,
},
],
});
@@ -272,8 +274,8 @@ export default class BillAllocateLandedCost extends BaseController {
errors: [
{
type: 'BILL_LANDED_COST_NOT_FOUND',
code: 200,
message: 'The given bill located landed cost not found.',
code: 600,
},
],
});

View File

@@ -1,19 +1,31 @@
exports.up = function(knex) {
exports.up = function (knex) {
return knex.schema.createTable('items_entries', (table) => {
table.increments();
table.string('reference_type').index();
table.string('reference_id').index();
table.integer('index').unsigned();
table.integer('item_id').unsigned().index().references('id').inTable('items');
table
.integer('item_id')
.unsigned()
.index()
.references('id')
.inTable('items');
table.text('description');
table.integer('discount').unsigned();
table.integer('quantity').unsigned();
table.integer('rate').unsigned();
table.integer('sell_account_id').unsigned().references('id').inTable('accounts');
table.integer('cost_account_id').unsigned().references('id').inTable('accounts');
table
.integer('sell_account_id')
.unsigned()
.references('id')
.inTable('accounts');
table
.integer('cost_account_id')
.unsigned()
.references('id')
.inTable('accounts');
table.boolean('landed_cost').defaultTo(false);
table.decimal('allocated_cost_amount', 13, 3);
@@ -21,6 +33,6 @@ exports.up = function(knex) {
});
};
exports.down = function(knex) {
exports.down = function (knex) {
return knex.schema.dropTableIfExists('items_entries');
};

View File

@@ -82,4 +82,12 @@ export interface IBillLandedCostTransaction {
allocationMethod: string;
costAccountId: number,
description: string;
};
allocatedEntries?: IBillLandedCostTransactionEntry[],
};
export interface IBillLandedCostTransactionEntry {
cost: number;
entryId: number;
billLocatedCostId: number,
}

View File

@@ -19,10 +19,19 @@ export default class BillLandedCost extends TenantModel {
/**
* Relationship mapping.
*/
static get relationMappings() {
static get relationMappings() {
const BillLandedCostEntry = require('models/BillLandedCostEntry');
const Bill = require('models/Bill');
return {
bill: {
relation: Model.BelongsToOneRelation,
modelClass: Bill.default,
join: {
from: 'bill_located_costs.billId',
to: 'bills.id',
},
},
allocateEntries: {
relation: Model.HasManyRelation,
modelClass: BillLandedCostEntry.default,

View File

@@ -8,11 +8,13 @@ import {
IBillLandedCost,
ILandedCostItemDTO,
ILandedCostDTO,
IBillLandedCostTransaction,
IBillLandedCostTransactionEntry,
} from 'interfaces';
import InventoryService from 'services/Inventory/Inventory';
import HasTenancyService from 'services/Tenancy/TenancyService';
import { ERRORS } from './constants';
import { mergeObjectsBykey } from 'utils';
import { transformToMap } from 'utils';
import JournalPoster from 'services/Accounting/JournalPoster';
import JournalEntry from 'services/Accounting/JournalEntry';
import TransactionLandedCost from './TransctionLandedCost';
@@ -141,7 +143,10 @@ export default class AllocateLandedCostService {
transactionId: number,
amount: number
) => {
const Model = this.transactionLandedCost.getModel(tenantId, transactionType);
const Model = this.transactionLandedCost.getModel(
tenantId,
transactionType
);
// Decrement the allocate cost amount of cost transaction.
return Model.query()
@@ -216,22 +221,6 @@ export default class AllocateLandedCostService {
return sumBy(landedCostDTO.items, 'cost');
};
/**
* Validate allocate cost transaction should not be bill transaction.
* @param {number} purchaseInvoiceId
* @param {string} transactionType
* @param {number} transactionId
*/
private validateAllocateCostNotSameBill = (
purchaseInvoiceId: number,
transactionType: string,
transactionId: number
): void => {
if (transactionType === 'Bill' && transactionId === purchaseInvoiceId) {
throw new ServiceError(ERRORS.ALLOCATE_COST_SHOULD_NOT_BE_BILL);
}
};
/**
* Validates the landed cost entry amount.
* @param {number} unallocatedCost -
@@ -248,6 +237,24 @@ export default class AllocateLandedCostService {
}
};
/**
* Merges item entry to bill located landed cost entry.
* @param {IBillLandedCostTransactionEntry[]} locatedEntries -
* @param {IItemEntry[]} billEntries -
* @returns {(IBillLandedCostTransactionEntry & { entry: IItemEntry })[]}
*/
private mergeLocatedWithBillEntries = (
locatedEntries: IBillLandedCostTransactionEntry[],
billEntries: IItemEntry[]
): (IBillLandedCostTransactionEntry & { entry: IItemEntry })[] => {
const billEntriesByEntryId = transformToMap(billEntries, 'id');
return locatedEntries.map((entry) => ({
...entry,
entry: billEntriesByEntryId.get(entry.entryId),
}));
};
/**
* Records inventory transactions.
* @param {number} tenantId
@@ -255,25 +262,24 @@ export default class AllocateLandedCostService {
*/
private recordInventoryTransactions = async (
tenantId: number,
allocateEntries,
purchaseInvoice: IBill,
landedCostId: number
billLandedCost: IBillLandedCostTransaction,
bill: IBill
) => {
const costEntries = mergeObjectsBykey(
purchaseInvoice.entries,
allocateEntries.map((e) => ({ ...e, id: e.itemId })),
'id'
// Retrieve the merged allocated entries with bill entries.
const allocateEntries = this.mergeLocatedWithBillEntries(
billLandedCost.allocateEntries,
bill.entries
);
// Inventory transaction.
const inventoryTransactions = costEntries.map((entry) => ({
date: purchaseInvoice.billDate,
itemId: entry.itemId,
// Mappes the allocate cost entries to inventory transactions.
const inventoryTransactions = allocateEntries.map((allocateEntry) => ({
date: bill.billDate,
itemId: allocateEntry.entry.itemId,
direction: 'IN',
quantity: 0,
rate: entry.cost,
rate: allocateEntry.cost,
transactionType: 'LandedCost',
transactionId: landedCostId,
entryId: entry.id,
transactionId: billLandedCost.id,
entryId: allocateEntry.entryId,
}));
return this.inventoryService.recordInventoryTransactions(
@@ -345,12 +351,11 @@ export default class AllocateLandedCostService {
purchaseInvoiceId
);
// Records the inventory transactions.
// await this.recordInventoryTransactions(
// tenantId,
// allocateCostDTO.items,
// purchaseInvoice,
// landedCostTransaction.id
// );
await this.recordInventoryTransactions(
tenantId,
billLandedCost,
purchaseInvoice
);
// Increment landed cost amount on transaction and entry.
await this.incrementLandedCostAmount(
tenantId,
@@ -360,7 +365,7 @@ export default class AllocateLandedCostService {
amount
);
// Write the landed cost journal entries.
// await this.writeJournalEntry(tenantId, purchaseInvoice, billLandedCost);
// await this.writeJournalEntry(tenantId, billLandedCost, purchaseInvoice);
return { billLandedCost };
};
@@ -373,6 +378,7 @@ export default class AllocateLandedCostService {
*/
private writeJournalEntry = async (
tenantId: number,
landedCostEntry: any,
purchaseInvoice: IBill,
landedCost: IBillLandedCost
) => {