Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ public record PricingCostingItemDto(
/** V156: non-null when the freight table could not be looked up for this line (no
* thickness_mm or no origin country on the catalogue row), in which case every
* shipment-derived cost above is null and the CEO must supply one before approval. */
String uncostableReason
String uncostableReason,
/** Comma-separated codes behind {@code uncostableReason}: MISSING_SQM, MISSING_THICKNESS, MISSING_ORIGIN, NO_FREIGHT_BAND. */
String uncostableCode
) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public void replaceItemsPreservingOverrides(long costingId, List<PricingCostingW
calculation_config_id, calculation_config_version, goods_cost_thb, freight_cost_thb,
insurance_cost_thb, import_duty_thb, inland_transport_cost_thb, other_cost_thb,
cif_cost_thb, landed_cost_per_unit_thb, total_landed_cost_thb, clearance_fee_thb,
product_type, calculated_at, calculation_snapshot, uncostable_reason)
product_type, calculated_at, calculation_snapshot, uncostable_reason, uncostable_code)
VALUES
(:costingId, :pricingRequestItemId, :factoryQuoteId, :factoryQuoteItemId,
:factoryQuoteRevisionNo, :factoryId, :factoryName, :supplierQuoteRef, :rawUnitPrice,
Expand All @@ -135,7 +135,7 @@ public void replaceItemsPreservingOverrides(long costingId, List<PricingCostingW
:calculationConfigId, :calculationConfigVersion, :goodsCostThb, :freightCostThb,
:insuranceCostThb, :importDutyThb, :inlandTransportCostThb, :otherCostThb,
:cifCostThb, :landedCostPerUnitThb, :totalLandedCostThb, :clearanceFeeThb,
:productType, now(), CAST(:calculationSnapshot AS jsonb), :uncostableReason)
:productType, now(), CAST(:calculationSnapshot AS jsonb), :uncostableReason, :uncostableCode)
ON CONFLICT (pricing_costing_id, pricing_request_item_id) DO UPDATE SET
factory_quote_id = EXCLUDED.factory_quote_id,
factory_quote_item_id = EXCLUDED.factory_quote_item_id,
Expand Down Expand Up @@ -173,7 +173,8 @@ ON CONFLICT (pricing_costing_id, pricing_request_item_id) DO UPDATE SET
product_type = EXCLUDED.product_type,
calculated_at = EXCLUDED.calculated_at,
calculation_snapshot = EXCLUDED.calculation_snapshot,
uncostable_reason = EXCLUDED.uncostable_reason
uncostable_reason = EXCLUDED.uncostable_reason,
uncostable_code = EXCLUDED.uncostable_code
""", batch);

// Drop any line the recalculation no longer produces (the pricing request lost an item
Expand Down Expand Up @@ -280,7 +281,7 @@ public List<PricingCostingItemDto> findItems(long costingId) {
landed_cost_per_unit_thb, total_landed_cost_thb, clearance_fee_thb, product_type,
calculated_at, calculation_snapshot::text AS calculation_snapshot,
manual_landed_cost_per_unit_thb, override_reason, overridden_by, overridden_at,
override_fx_rate, override_calc_config_version, uncostable_reason
override_fx_rate, override_calc_config_version, uncostable_reason, uncostable_code
FROM sales.pricing_costing_item
WHERE pricing_costing_id = :costingId
ORDER BY pricing_costing_item_id
Expand Down Expand Up @@ -396,7 +397,8 @@ private PricingCostingItemDto mapItem(ResultSet rs) throws SQLException {
effectiveLandedCostPerUnitThb,
effectiveTotalLandedCostThb,
overrideStale,
rs.getString("uncostable_reason")
rs.getString("uncostable_reason"),
rs.getString("uncostable_code")
);
}

Expand Down Expand Up @@ -449,7 +451,8 @@ public record PricingCostingWriteItem(
String calculationSnapshot,
/** V156: non-null when the freight table could not be looked up; every shipment-derived
* cost above is then null. Enforced as an XOR by chk_pricing_costing_item_uncostable_xor. */
String uncostableReason
String uncostableReason,
String uncostableCode
) {
MapSqlParameterSource toParams(long costingId) {
return new MapSqlParameterSource()
Expand Down Expand Up @@ -490,7 +493,8 @@ MapSqlParameterSource toParams(long costingId) {
.addValue("clearanceFeeThb", clearanceFeeThb)
.addValue("productType", productType)
.addValue("calculationSnapshot", calculationSnapshot == null ? "{}" : calculationSnapshot)
.addValue("uncostableReason", uncostableReason);
.addValue("uncostableReason", uncostableReason)
.addValue("uncostableCode", uncostableCode);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,16 @@
import org.springframework.web.bind.annotation.RestController;
import th.co.glr.hr.auth.SessionContext;
import th.co.glr.hr.auth.UserPrincipal;
import th.co.glr.hr.pricingdecision.PricingDecisionDtos.CeoFixResult;
import th.co.glr.hr.pricingdecision.PricingDecisionDtos.PricingDecisionDto;
import th.co.glr.hr.pricingdecision.PricingDecisionDtos.PricingDecisionSalesViewDto;
import th.co.glr.hr.pricingdecision.PricingDecisionRequests.ApprovePricingDecisionRequest;
import th.co.glr.hr.pricingdecision.PricingDecisionRequests.CostOverrideRequest;
import th.co.glr.hr.pricingdecision.PricingDecisionRequests.FreightRequest;
import th.co.glr.hr.pricingdecision.PricingDecisionRequests.OriginCountryRequest;
import th.co.glr.hr.pricingdecision.PricingDecisionRequests.ProductTypeOverrideRequest;
import th.co.glr.hr.pricingdecision.PricingDecisionRequests.RenameItemRequest;
import th.co.glr.hr.pricingdecision.PricingDecisionRequests.RepointFactoryRequest;
import th.co.glr.hr.pricingdecision.PricingDecisionRequests.ReturnPricingDecisionRequest;
import th.co.glr.hr.pricingdecision.PricingDecisionRequests.StartPricingDecisionRequest;
import th.co.glr.hr.pricingdecision.PricingDecisionRequests.UpdatePricingDecisionRequest;
Expand Down Expand Up @@ -98,6 +103,51 @@ Map<String, PricingDecisionDto> overrideItemProductType(
return Map.of("decision", decisions.overrideItemProductType(decisionId, itemId, request, user));
}

// CEO price-review fixes, keyed by the pricing request (the CEO edits the request's data, not the decision).
@PutMapping("/pricing-requests/{id}/factory-quotes/{factoryQuoteId}/factory")
CeoFixResult repointFactoryQuote(
@PathVariable long id,
@PathVariable long factoryQuoteId,
@RequestBody RepointFactoryRequest request,
HttpSession session
) {
UserPrincipal user = sessions.requireUser(session);
return decisions.repointFactoryQuote(id, factoryQuoteId, request, user);
}

@PutMapping("/pricing-requests/{id}/items/{itemId}/origin-country")
CeoFixResult setItemOriginCountry(
@PathVariable long id,
@PathVariable long itemId,
@RequestBody OriginCountryRequest request,
HttpSession session
) {
UserPrincipal user = sessions.requireUser(session);
return decisions.setItemOriginCountry(id, itemId, request, user);
}

@PutMapping("/pricing-requests/{id}/items/{itemId}/freight")
CeoFixResult setItemFreight(
@PathVariable long id,
@PathVariable long itemId,
@RequestBody FreightRequest request,
HttpSession session
) {
UserPrincipal user = sessions.requireUser(session);
return decisions.setItemFreight(id, itemId, request, user);
}

@PutMapping("/pricing-requests/{id}/items/{itemId}/name")
CeoFixResult renameItem(
@PathVariable long id,
@PathVariable long itemId,
@RequestBody RenameItemRequest request,
HttpSession session
) {
UserPrincipal user = sessions.requireUser(session);
return decisions.renameItem(id, itemId, request, user);
}

@PostMapping("/pricing-decisions/{decisionId}/approve")
Map<String, PricingDecisionDto> approve(
@PathVariable long decisionId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,4 +185,9 @@ public record PricingDecisionSalesItemDto(
BigDecimal approvedSellingPricePerRequestedUnit,
BigDecimal minimumSellingPricePerRequestedUnit
) {}

/** CEO price-review fix result: the saved fix always stands; {@code costingError} is the recalculation's
* 422 message when cost could not be recomputed (the CEO fixes the next problem and goes again);
* {@code decision} is null when no decision exists yet (request still READY_FOR_CEO_REVIEW). */
public record CeoFixResult(PricingDecisionDto decision, String costingError) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,16 @@ public record CostOverrideRequest(BigDecimal manualLandedCostPerUnitThb, String
* formula-derived and auditable from the product_type alone, recorded on the row itself
* ({@code pricing_costing_item.product_type}), not just in the event trail. */
public record ProductTypeOverrideRequest(String productType) {}

/** CEO fix: re-point a factory quote to a master {@code price_catalog.factories} row. */
public record RepointFactoryRequest(Long factoryId) {}

/** CEO fix: set a line's ประเทศต้นทาง (the sales form's vocabulary: อิตาลี/สเปน/จีน/ไทย-สต็อก). */
public record OriginCountryRequest(String originCountry) {}

/** CEO fix: rename a line (ยี่ห้อ + รุ่น); at least one must be non-blank. */
public record RenameItemRequest(String brand, String model) {}

/** CEO fix: the freight (THB, TOTAL for the line) for a line the freight table has no band for; null clears it. */
public record FreightRequest(BigDecimal freightThb) {}
}
Loading
Loading