Skip to content

release: develop → main (2026-10-30) - #1209

Merged
waritctd merged 34 commits into
mainfrom
release/2026-10-30-develop-to-main
Oct 30, 2026
Merged

waritctd merged 34 commits into
mainfrom
release/2026-10-30-develop-to-main

Conversation

@waritctd

Copy link
Copy Markdown
Owner

Forwards develop to main: the sales-pipeline fixes from the 29–30 Oct UI walks.

Carries

Main's #1200 release, the README commit, and render.yaml are merged in; the image tag conflict resolves to the new tag.

Deploy order

  • Migrations:
    • V201__stock_line_backfill (prod). A read-only prod check on 30 Oct found 0 deals on the payment track and 0 stock pricing-request lines, so it changes no prod rows.
    • V200.1 is demo-only and never runs on prod.
  • Backend changed, so a new image is needed. render.yaml now points at ghcr.io/waritctd/glr-hr-backend:v2026-10-30.
  • Before merging: build and push v2026-10-30 (linux/amd64, all 12 licensed fonts including cordia.ttc), switch Render to it, and check health. A merge to main deploys the frontend only (Vercel).

🤖 Generated with Claude Code

waritctd and others added 30 commits October 29, 2026 17:00
…move, tidier จัดซื้อ-ส่งมอบ tab

Owner rulings 2026-10-29 after a ui-revamp audit and a before/after mock of
the live page:
- One name and one word: the ขั้น 11 main button reads ออกใบขอซื้อ (IR); the
  fulfilment labels, header chip and both TicketService messages say ใบขอซื้อ.
- Pipeline owner: ขั้น 11 stays ฝ่ายบัญชี, ขั้น 12 shows ฝ่ายขาย (display only).
- W3-09: at ขั้น 12 the manual move to 13 is a secondary
  "ข้ามไปขั้น 13 ด้วยตนเอง".
- จัดซื้อ-ส่งมอบ tab: before the first IR the IR box comes first and the
  import-progress chips are hidden (stock reservation and commission weight
  stay reachable below it); the required-by field folds behind a toggle; when
  no factory is left (new read-only hasUncoveredFactories on the IR list) the
  create controls give way to "ทุกโรงงานออกใบขอซื้อแล้ว" (or
  "ไม่มีรายการที่ต้องออกใบขอซื้อ" with nothing to import).
- The order-email button and line are gone from the sales rep's deal-tab
  cards (CEO and the import pages keep it); no ✉ emoji.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…batch 1)

Owner rulings 2026-10-29 for UI-walk findings QA-16/19/22/25/26/27:

- QA-25: new deal codes are DL-YYYY-NNNN (was PR-, clashing with PCR-).
  Existing codes are untouched.
- QA-16: the payment chip reads ยังไม่ถึงขั้นชำระ before the order is
  confirmed, ไม่เก็บมัดจำ for a bypass/0% deposit deal before goods arrive,
  and รอชำระส่วนที่เหลือ once the track reaches AWAITING_FINAL_PAYMENT.
  Legacy deals past ORDER_RECEIVED keep the old derivation.
- QA-22: the การนำเข้า chip follows the per-factory IR steps (slowest
  ISSUED factory, plus "· ถึงโกดัง X/Y" when there are several). Stored IRs
  load for every role ImportRequestService allows to read them.
- QA-19: account only gets forward stage moves: no backward ADVANCE_STAGE,
  the update-stage form lists only stages ahead, and the server returns 409.
- QA-26/27: the legacy ticket.status is no longer shown in the deal header
  or deal list; the "รอ CEO ตรวจสอบปิดงาน" banner ends when the deal is
  COMPLETED.
- QA-26: demo migration V200.1 removes DEMO-TKT-02/03/04 (guarded; no-op
  where absent or worked on).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… branch

Code review of #1201:
- GET /api/tickets/{id}/import-requests is back to rows only, so the import
  pages (one call per deal) no longer pay for the coverage check.
- New read-only GET /api/tickets/{ticketId}/import-requests/coverage returns
  ImportRequestCoverageResponse(hasUncoveredFactories), same authz as the list;
  typed, so the API contract guards see it. Both digests regenerated (+1 op).
- The panel asks the coverage endpoint once (same cache prefix, so IR changes
  still refresh it) instead of fetching the list twice.
- Removed the unreachable 'ยังไม่ออกใบขอซื้อ' paragraph inside the
  นำเข้าสินค้า card.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(deal): ขั้น 11/12 deal page — one IR name, owner, demoted manual move, tidier จัดซื้อ-ส่งมอบ tab
…ix/p2-batch1-deal-chips

# Conflicts:
#	frontend/src/features/tickets/DealStateHeader.jsx
#	frontend/src/features/tickets/DealStateHeader.test.jsx
#	frontend/src/utils/format.test.js
- The "รอ CEO ตรวจสอบปิดงาน" blocker shows only on an ACTIVE deal: the CEO can
  only verify an ACTIVE deal, so a cancelled/lost/paused deal with a close
  confirmation no longer reads as waiting for the CEO.
- The การนำเข้า chip's tone follows the per-factory label: every factory at
  the warehouse reads success, a factory still on the way reads info.
- The account backward-stage 409 now sits in updateStageInternal next to its
  own summary read, instead of loading the whole ticket a second time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(deals): status chips and labels follow the deal's real state (P2 batch 1)
…visited stages

P2 batch 3 from the skip walk, owner rulings 2026-10-29:
- SK-03: the route-choice menu (2+ parties left) has the neutral trigger
  เสนอราคา instead of the first party's name; dashboard label unchanged.
- SK-05: the stage track marks ข้าม on on-route stages below the current one
  that the deal never sat on (STAGE_CHANGED toStatus); the first change's
  fromStatus and earlier count as done. Phase headers count skips.
- SK-06: skipped owner stage stays final (server gate unchanged); the
  แก้ไขสถานะ modal now words stages by the deal's channel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kips nothing

Review follow-ups on #1206: a done phase whose on-route stages were all
skipped no longer shows the done tick; a first STAGE_CHANGED whose
fromStatus is outside the catalog counts the history as done; the
skipped-stage filter uses its own index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(deal): skip route reads true — เสนอราคา ▾ trigger, ข้าม on never-visited stages
Owner rulings 2026-10-29:
- Account รอรับมัดจำ = deposit due (latest ISSUED deposit notice total_payable,
  new TicketSummaryDto.depositDue, hidden from import).
- ค้างรับ = /finance คงค้างรวม on account, CEO and SM (shared dashboardMoney.js).
- Account รอชำระส่วนที่เหลือ counts the deals the to-do offers that step for.
- CEO + SM show เงินรับแล้ว (เดือนนี้) (receipts in the Bangkok month, new
  cashReceivedThisMonth on the dashboard summary for account/ceo/sales_manager),
  ค้างรับ and ยอดคาดการณ์ (ACTIVE deals before ขั้น 10). Old month-sales,
  closed-count and pipeline tiles removed.
- CEO ยอดตามทีม/ฝ่าย = this month's cash per rep (cashReceivedByRep).
- Paid-sum sign rule shared via TicketRepository.SIGNED_RECEIPT_SUM.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- SM leaderboard = this month's cash per rep (same rows as the CEO panel)
- cashReceivedThisMonth = sum of the per-rep rows (one query)
- pin the rep panel's largest-first order; drop unused DashboardSummaryDto.of overload; fix stale comments

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cap)

financeOutstanding / forecastValue on /api/dashboard/summary for account/ceo/sales_manager,
one SQL reusing payableAmountSelect, paidAmountSelect, paymentOverduePredicate, the account
list scope and the commission-recorded fragment. Account, CEO, SM and the /finance header
read the same figure (CEO /finance hero relabelled ค้างรับทั้งหมด). Shared case table
money-cases.json pins the SQL against nextAccountAction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y cache key

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nance

fix(dashboard): money tiles match finance (QA-17, QA-18)
…ขั้น 13 (walk 4)

Owner rulings 2026-10-29 (no reserve feature):
- confirmOrder writes ticket_item.qty_from_stock = qty for IN_THAILAND PCR lines
  (0 otherwise), so IR candidates, the all-stock 409, commission's stock share
  and STOCK delivery read it unchanged. issue() refuses a draft with any
  stock-covered line.
- All-stock deals route to DELIVERY_SCHEDULING/FROM_STOCK on deposit confirm,
  0% confirmation, or waiver. STOCK delivery waits for a settled deposit.
- RESERVE_STOCK is no longer advertised; the จองสินค้าจากสต็อก UI is removed
  (endpoint kept).
- W4-01: stock lines store no origin/lead time and print no ระยะเวลานำเข้า;
  จากสต็อก badge; import not prompted for stock lines.
- W4-03: CEO can start a new review after a returned decision.
- W4-04: no PCR create/revise/submit once the order is confirmed (409), UI hidden;
  ⋯ ขอแก้ไข hidden after the order. New summary field ticketPaymentStatus.
- W4-05: 0%-deposit deal gets the IR main button; ถัดไป skips ขั้น 11.
- W4-06: ตีกลับ hidden on an all-stock request.
- W4-09: sales-typed stock price removed (stored NULL); deal shows CEO price.
- IN_TRANSIT refused (400); dead in-transit service code deleted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…for no-deposit new-engine deals

Code review of #1204:
- V201 backfill: confirmed IN_THAILAND lines on live deals get qty_from_stock = qty
  (never lines on an ISSUED IR or mapped as an import line); settled all-stock
  deals route to DELIVERY_SCHEDULING/FROM_STOCK with a STAGE_CHANGED event.
- Payment route only once the deposit is settled; reconcile keeps qty_from_stock
  on non-stock lines; IR main action hidden when every line is stock.
- One depositSettled predicate per side; STOCK_IN_THAILAND constant.

W5-01: a 0% / WAIVED / CREDIT_CUSTOMER deal on a new-engine quotation can issue its
remaining invoice: net = the quotation's stored total, VAT at its document
language's rate (EN 0%), lines = the quotation's own stored lines (ส่วนลดพิเศษ as
its own line), same quotation pick as payable; NULL total refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(stock): stock lines never go to a factory; all-stock deals go to ขั้น 13 (walk 4)
Update stack/prereqs, test and Vercel notes. Add mock-mode and
real-backend (demo profile) quick-start with quick-login accounts and
how to load the price catalogue, which the demo seed does not include.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Owner rulings 2026-10-29/30:
- QA-12: ผู้รับคำขอราคา is locked (with a hint to create a new PCR) in revision
  mode and when editing a revision child's draft, matching the backend's GLA-102
  409. Backend unchanged.
- QA-28: item size is centimetres everywhere. The deal item field is ขนาด (ซม.)
  (hint เช่น 60x120); a deal catalogue pick and the catalogue dropdown rows on
  both the deal and the quote/PCR forms use sizeTextFromCatalog (cm). Existing
  rows are not rewritten.
- W3-06/QA-35: ลูกค้าปฏิเสธ / ลูกค้าขอแก้ไข on the PCR page (both engines) and the
  deal page's DealQuotationPanel open a confirm dialog with a required reason
  (saved as customerNote). Each outcome has its own clientRequestId, rotated only
  on success: the backend replays a reused key as the FIRST outcome's success.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sonConfirmCopy

The deal panel and the PCR detail page rendered the same ปฏิเสธ / ขอแก้ไข
ConfirmDialog copy inline; move it next to acceptOutcomeConfirmCopy in
quotationMeta so the two cannot drift. Copy and props are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ize fallback

- Outcome idempotency keys are per (quotation, outcome) instead of per outcome:
  a lost-response ปฏิเสธ on one quotation no longer leaves its key to be reused on
  a later revision (backend 409 "clientRequestId ถูกใช้ไปแล้วกับใบเสนอราคาอื่น").
- DealQuotationPanel captures the quotation when ปฏิเสธ / ขอแก้ไข is clicked, so a
  refetch while the dialog is open cannot retarget the recorded outcome.
- Both reason dialogs close only on success; a failed call keeps the typed reason
  for a same-key retry.
- sizeTextFromCatalog: a blank sizeRaw no longer shadows `size` on a row with no
  dimensions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(sales): P2 batch 4 — PCR/quotation forms (QA-12, QA-28, W3-06/QA-35)
The §5 advance-notice gate (VACATION 3, PERSONAL 1) compared calendar
dates, so Saturday/Sunday and holidays counted toward the notice and a
late vacation request went through without a warning.

Now the days after today up to the leave's first working day must number
at least advance_notice_days, using the employee's own schedule and
hr.holiday. A start on a day the employee does not work (weekend for a
Mon-Fri person, or a holiday) counts to their first working day in the
leave; a six-day employee's Saturday counts. A miss is still
WARN_UNPAID_ALL, not a block. Message copy now says "วันทำงาน".

Owner ruling 2026-10-29.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Code review of #1203: submit/preview now build one predicate over
[earlier of start and today+1, end] and pass it to autoRejectNote, so the
notice gate no longer re-queries the employee and holidays. Tests pin a
today-holiday start (counts to the next working day), match the notice
stub on the employee id, and assert a single predicate lookup per submit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…em-393023

fix(leave): advance notice counts the employee's working days
Owner ruling 2026-10-30: since #1207 (QA-28), deal item sizes are cm text
("20x30.5"), and the factory-facing IR printed them with no unit.

- At IR creation from the deal, a line linked to a catalogue row stores that row's
  own cm size (pp.size_cm, V174: width_mm/height_mm ÷ 10) instead of the typed
  text, in the shared factoryResolutionCandidates query. Editing a deal line
  clears its catalogue link, so a retyped size is never overridden.
- At render time only (stored size and DTO stay raw), the email "Size:" line and
  the IR PDF size column append " cm" to a unitless size. A size that already
  carries a unit prints as typed, and a blank size prints nothing.
- The unit regex moves from QuotationRenderer into one shared SizeUnit helper,
  which QuotationRenderer now uses; its " cm." suffix is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
waritctd and others added 4 commits October 30, 2026 02:37
…e project imports

Code-review follow-ups on #1208 (findings 3 and 5).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(import): IR factory email and PDF print item size in cm
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…velop-to-main

Keeps render.yaml on the new backend image v2026-10-30.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
demo-glr Ready Ready Preview Oct 30, 2026 3:22am UTC

Request Review

This branch was successfully deployed

1 active deployment
Preview — 315cc146 Deployed Oct 30, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant