feat: restructure sales, add PDF quote generation and WebSocket support
This commit is contained in:
@@ -23,6 +23,8 @@ export class ForecastProductController {
|
||||
public catalogItemIdentifier: string | null;
|
||||
|
||||
public productDescription: string;
|
||||
public customerDescription: string | null;
|
||||
public productNarrative: string | null;
|
||||
public productClass: string;
|
||||
public forecastType: string;
|
||||
|
||||
@@ -74,6 +76,9 @@ export class ForecastProductController {
|
||||
this.catalogItemIdentifier = data.catalogItem?.identifier ?? null;
|
||||
|
||||
this.productDescription = data.productDescription;
|
||||
this.customerDescription = data.customerDescription ?? null;
|
||||
this.productNarrative =
|
||||
data.customFields?.find((f) => f.id === 46)?.value?.toString() ?? null;
|
||||
this.productClass = data.productClass;
|
||||
this.forecastType = data.forecastType;
|
||||
|
||||
@@ -118,6 +123,24 @@ export class ForecastProductController {
|
||||
* Enriches this forecast product with cancellation data from the
|
||||
* procurement products endpoint.
|
||||
*/
|
||||
/**
|
||||
* Apply Procurement Custom Fields
|
||||
*
|
||||
* Enriches this forecast product with custom field data from the
|
||||
* procurement products endpoint (the forecast endpoint does not
|
||||
* return customFields).
|
||||
*/
|
||||
public applyProcurementCustomFields(data: {
|
||||
customFields?: Array<{ id: number; value?: unknown }>;
|
||||
}): void {
|
||||
const narrative = data.customFields
|
||||
?.find((f) => f.id === 46)
|
||||
?.value?.toString();
|
||||
if (narrative) {
|
||||
this.productNarrative = narrative;
|
||||
}
|
||||
}
|
||||
|
||||
public applyCancellationData(data: {
|
||||
cancelledFlag?: boolean;
|
||||
quantityCancelled?: number;
|
||||
@@ -154,6 +177,38 @@ export class ForecastProductController {
|
||||
return this.revenue - this.cost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Effective Quantity
|
||||
*
|
||||
* Returns the quantity adjusted for cancellations (minimum 0).
|
||||
*/
|
||||
public get effectiveQuantity(): number {
|
||||
if (this.cancellationType === "full") return 0;
|
||||
return Math.max(0, this.quantity - this.quantityCancelled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Effective Revenue
|
||||
*
|
||||
* Returns the revenue adjusted proportionally for cancelled units.
|
||||
*/
|
||||
public get effectiveRevenue(): number {
|
||||
if (this.cancellationType === "full" || this.quantity <= 0) return 0;
|
||||
const unitPrice = this.revenue / this.quantity;
|
||||
return unitPrice * this.effectiveQuantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Effective Cost
|
||||
*
|
||||
* Returns the cost adjusted proportionally for cancelled units.
|
||||
*/
|
||||
public get effectiveCost(): number {
|
||||
if (this.cancellationType === "full" || this.quantity <= 0) return 0;
|
||||
const unitCost = this.cost / this.quantity;
|
||||
return unitCost * this.effectiveQuantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancelled
|
||||
*
|
||||
@@ -201,12 +256,17 @@ export class ForecastProductController {
|
||||
? { id: this.catalogItemCwId, identifier: this.catalogItemIdentifier }
|
||||
: null,
|
||||
productDescription: this.productDescription,
|
||||
customerDescription: this.customerDescription,
|
||||
productNarrative: this.productNarrative,
|
||||
productClass: this.productClass,
|
||||
forecastType: this.forecastType,
|
||||
revenue: this.revenue,
|
||||
cost: this.cost,
|
||||
margin: this.margin,
|
||||
profit: this.profit,
|
||||
effectiveQuantity: this.effectiveQuantity,
|
||||
effectiveRevenue: this.effectiveRevenue,
|
||||
effectiveCost: this.effectiveCost,
|
||||
percentage: this.percentage,
|
||||
includeFlag: this.includeFlag,
|
||||
linkFlag: this.linkFlag,
|
||||
|
||||
Reference in New Issue
Block a user