mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 20:30:33 +00:00
WIP: Allocate landed cost.
This commit is contained in:
@@ -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,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
@@ -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');
|
||||
};
|
||||
|
||||
@@ -82,4 +82,12 @@ export interface IBillLandedCostTransaction {
|
||||
allocationMethod: string;
|
||||
costAccountId: number,
|
||||
description: string;
|
||||
};
|
||||
|
||||
allocatedEntries?: IBillLandedCostTransactionEntry[],
|
||||
};
|
||||
|
||||
export interface IBillLandedCostTransactionEntry {
|
||||
cost: number;
|
||||
entryId: number;
|
||||
billLocatedCostId: number,
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
) => {
|
||||
|
||||
Reference in New Issue
Block a user