cost rollups
This commit is contained in:
@@ -134,6 +134,28 @@ type ProjectReceiptLineRecord = {
|
||||
};
|
||||
};
|
||||
|
||||
type ProjectCostWorkOrderRecord = {
|
||||
quantity: number;
|
||||
completedQuantity: number;
|
||||
item: {
|
||||
bomLines: Array<{
|
||||
quantity: number;
|
||||
componentItem: {
|
||||
defaultCost: number | null;
|
||||
};
|
||||
}>;
|
||||
};
|
||||
operations: Array<{
|
||||
plannedMinutes: number;
|
||||
}>;
|
||||
materialIssues: Array<{
|
||||
quantity: number;
|
||||
componentItem: {
|
||||
defaultCost: number | null;
|
||||
};
|
||||
}>;
|
||||
};
|
||||
|
||||
function roundMoney(value: number) {
|
||||
return Math.round(value * 100) / 100;
|
||||
}
|
||||
@@ -327,6 +349,44 @@ async function buildProjectCockpit(record: ProjectRecord, rollups: ProjectRollup
|
||||
: Promise.resolve([]),
|
||||
record.salesOrder ? getSalesOrderPlanningById(record.salesOrder.id) : Promise.resolve(null),
|
||||
]);
|
||||
const workOrderCosts = await prisma.workOrder.findMany({
|
||||
where: {
|
||||
projectId: record.id,
|
||||
},
|
||||
select: {
|
||||
quantity: true,
|
||||
completedQuantity: true,
|
||||
item: {
|
||||
select: {
|
||||
bomLines: {
|
||||
select: {
|
||||
quantity: true,
|
||||
componentItem: {
|
||||
select: {
|
||||
defaultCost: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
operations: {
|
||||
select: {
|
||||
plannedMinutes: true,
|
||||
},
|
||||
},
|
||||
materialIssues: {
|
||||
select: {
|
||||
quantity: true,
|
||||
componentItem: {
|
||||
select: {
|
||||
defaultCost: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const typedPurchaseOrders = purchaseOrders as ProjectPurchaseOrderRecord[];
|
||||
const typedReceiptLines = receiptLines as ProjectReceiptLineRecord[];
|
||||
@@ -334,6 +394,7 @@ async function buildProjectCockpit(record: ProjectRecord, rollups: ProjectRollup
|
||||
const typedSalesOrder = salesOrder as ProjectSalesDocumentRecord | null;
|
||||
const typedShipment = shipment as ProjectShipmentRecord | null;
|
||||
const typedPlanning = planning as SalesOrderPlanningDto | null;
|
||||
const typedWorkOrderCosts = workOrderCosts as ProjectCostWorkOrderRecord[];
|
||||
|
||||
const purchaseOrdersSummary: ProjectCockpitPurchaseOrderDto[] = typedPurchaseOrders.map((purchaseOrder) => {
|
||||
const linkedLineCount = purchaseOrder.lines.length;
|
||||
@@ -427,6 +488,30 @@ async function buildProjectCockpit(record: ProjectRecord, rollups: ProjectRollup
|
||||
|
||||
const commercialQuoteTotal = typedQuote ? calculateSalesDocumentTotal(typedQuote) : null;
|
||||
const commercialOrderTotal = typedSalesOrder ? calculateSalesDocumentTotal(typedSalesOrder) : null;
|
||||
const plannedMaterialCost = roundMoney(
|
||||
typedWorkOrderCosts.reduce((sum, workOrder) => (
|
||||
sum + workOrder.item.bomLines.reduce(
|
||||
(workOrderSum, bomLine) => workOrderSum + (bomLine.quantity * workOrder.quantity * (bomLine.componentItem.defaultCost ?? 0)),
|
||||
0
|
||||
)
|
||||
), 0)
|
||||
);
|
||||
const issuedMaterialCost = roundMoney(
|
||||
typedWorkOrderCosts.reduce((sum, workOrder) => (
|
||||
sum + workOrder.materialIssues.reduce(
|
||||
(workOrderSum, issue) => workOrderSum + (issue.quantity * (issue.componentItem.defaultCost ?? 0)),
|
||||
0
|
||||
)
|
||||
), 0)
|
||||
);
|
||||
const plannedOperationHours = roundMoney(
|
||||
typedWorkOrderCosts.reduce(
|
||||
(sum, workOrder) => sum + workOrder.operations.reduce((workOrderSum, operation) => workOrderSum + operation.plannedMinutes, 0),
|
||||
0
|
||||
) / 60
|
||||
);
|
||||
const buildQuantity = typedWorkOrderCosts.reduce((sum, workOrder) => sum + workOrder.quantity, 0);
|
||||
const completedBuildQuantity = typedWorkOrderCosts.reduce((sum, workOrder) => sum + workOrder.completedQuantity, 0);
|
||||
|
||||
return {
|
||||
commercial: {
|
||||
@@ -459,6 +544,16 @@ async function buildProjectCockpit(record: ProjectRecord, rollups: ProjectRollup
|
||||
.sort((left, right) => new Date(right.receivedAt).getTime() - new Date(left.receivedAt).getTime())
|
||||
.slice(0, 5),
|
||||
},
|
||||
costs: {
|
||||
quotedRevenue: commercialQuoteTotal,
|
||||
bookedRevenue: commercialOrderTotal,
|
||||
linkedPurchaseCommitment: linkedLineValue,
|
||||
plannedMaterialCost,
|
||||
issuedMaterialCost,
|
||||
plannedOperationHours,
|
||||
buildQuantity,
|
||||
completedBuildQuantity,
|
||||
},
|
||||
delivery: {
|
||||
shipmentNumber: typedShipment?.shipmentNumber ?? null,
|
||||
shipmentStatus: typedShipment?.status ?? null,
|
||||
|
||||
Reference in New Issue
Block a user