feat: add product to opportunity route, local product sequencing
- Add POST /v1/sales/opportunities/:identifier/products with field-level permission gating - Add CWForecastItemCreate type for forecast item creation - Store product display order locally (productSequence Int[] on Opportunity) - Rewrite resequenceProducts to be local-only (no CW PUT, stable IDs) - Remove reorderProducts CW util (PUT regenerated IDs & broke procurement) - Update fetchProducts to apply local ordering with CW sequenceNumber fallback - Add productSequence to OpportunityController.toJson() - Update API_ROUTES.md, PERMISSIONS.md, PermissionNodes.ts
This commit is contained in:
@@ -35,7 +35,15 @@ describe("memberCache", () => {
|
||||
test("stores and retrieves members", async () => {
|
||||
const members = new Collection<string, CWMember>();
|
||||
members.set("jroberts", buildTestMember());
|
||||
members.set("asmith", buildTestMember({ id: 20, identifier: "asmith", firstName: "Alice", lastName: "Smith" }));
|
||||
members.set(
|
||||
"asmith",
|
||||
buildTestMember({
|
||||
id: 20,
|
||||
identifier: "asmith",
|
||||
firstName: "Alice",
|
||||
lastName: "Smith",
|
||||
}),
|
||||
);
|
||||
|
||||
await setMemberCache(members);
|
||||
const cached = await getMemberCache();
|
||||
@@ -67,7 +75,10 @@ describe("memberCache", () => {
|
||||
|
||||
test("falls back to identifier if name parts are empty", async () => {
|
||||
const members = new Collection<string, CWMember>();
|
||||
members.set("empty", buildTestMember({ identifier: "empty", firstName: "", lastName: "" }));
|
||||
members.set(
|
||||
"empty",
|
||||
buildTestMember({ identifier: "empty", firstName: "", lastName: "" }),
|
||||
);
|
||||
await setMemberCache(members);
|
||||
|
||||
expect(resolveMemberName("empty")).toBe("empty");
|
||||
|
||||
Reference in New Issue
Block a user