Files
ARR-2.0-0918/.project-docs/40-domain/business-rules.md
T

11 KiB
Raw Blame History

Business Rules

Durable Rules

  • 2026-09-18用户明确的新自动入口:按所选日期通过OHIP查询本清单所需15个业务字段(不取Trace),直接交给数据处理入口, 沿用人工XML的业务规则。取得或重建XML不再是自动入口前提。用户要求本轮直接连接接口、跳过实际订单取数验证, 已完成的字段取数程序和本机检查见数据入口说明。下方原生报表/XML约定保留为人工入口及历史背景。

  • 用户已批准 XML 业务处理自动忽略表情。原文件字节与哈希保留;仅对可识别表情做文本清理/有限错误编码恢复,其他损坏编码、结构及业务校验照常拒绝。非零清理数量须可重放核对并提示;详见处理器 字段契约。本地4.1.0实现,线上部署另行执行。

  • 用户指定 ARR 源报表为 Arrivals: Detailed,前一日到店范围、全部预订/分房状态、全部代码,显示房号和 Resv. - GEN 备注并包含内部备注,以 XML 下载。完整参数以 ARR 源报表下载要求为唯一业务依据;接口下载尚未实现。

  • 源报表使用 Rate Code=ALL,现有费率白名单属于下载后处理。From Date/To Date 由上游系统按T-1规则传入明确日期; ARR直接使用并固定到批次,不自行计算昨日、转换时区或替换为营业日。当前单日任务要求两值有效且相等,缺失不补默认值。

  • Human access to the desktop Finance workspace, detailed health, generic business APIs, uploads, traces and downloads requires an authenticated ARR Web session. The H5 mobile dashboard is an intentional anonymous read-only exception: only its page/assets, /api/public/h5/months, /api/public/h5/analytics and no-detail /healthz are public; the H5 projection contains aggregate channel/room metrics and omits source hashes and operational metadata.

  • The single-operator login identity is injected as ARR_WEB_USERNAME / ARR_WEB_PASSWORD; real credentials are never stored in source or returned/logged. Missing credentials fail Web startup closed.

  • Login failures use a generic message and bounded attempt blocking. Logout revokes the server-side session; authenticated mutations continue to require CSRF.

  • The user uploads XML; the user does not submit a report year, report month, cutoff date, or separate monthly-generation request in the primary workflow.

  • Daily history and task trace show the validated browser-uploaded XML basename. Canonical internal source name source.xml is not user-facing; historical rows with no recorded basename display an unknown marker rather than a guessed filename.

  • Daily, monthly-publication and company-generation histories have independent viewing months and default to the most recent month containing that record type. Viewing-month state is read-only: it resets list paging but never changes monthly derivation or a company generation request. Company 生成月份 and history 查看月份 are separate inputs.

  • ARR's frozen processor generates complete structured data, which must be independently validated and successfully committed to the database before downstream monthly processing starts.

  • A non-empty set of errors made entirely of PRICE_UNMATCHED is the sole exception to immediate failure: it becomes a pending manual-price review and remains active without a Finance version, daily download, failure event or monthly trigger.

  • The review key is normalized company + Rate Code + Opera price. Staff may set only its non-negative integer price (including explicit 0); they may not change XML/company/rate/Opera fields or the fixed reference table. ARR stores the accepted integer as exact numeric(18,2) and freezes canonical .00 manifest text for deterministic replay.

  • Finalization freezes one canonical manifest bound to job, case, source SHA, business date, processor/rule identity and the complete key set, then replays original XML plus the fixed table. Only independently accepted final replay creates manual_review retained facts and one daily-commit event.

  • If the processor/rule identity changes while a case is open, staff must cancel and re-upload. Retryable infrastructure errors preserve the frozen manifest; deterministic final errors formally fail the case/run.

  • The production XML path must not require Agent, MCP, prompts, model-generated JSON, fetch grants, or a public source URL.

  • A successful database commit automatically triggers the monthly-report processing program through the business system.

  • Automatic monthly processing runs in a dedicated worker process, not inside the Web request process.

  • The worker derives the affected month from retained ARRIVAL facts belonging to the committed daily version.

  • The monthly as_of_date/“更新至” is the greatest ARRIVAL actually included in the current monthly snapshot. The XML filename and wall-clock date are never authorities for it.

  • Year, month, cutoff/as-of date, and similar fields are internal derived execution/audit values. Their presence in code or metadata does not make them user inputs.

  • The monthly output contains the exact business dimension/field TOTAL PRICE.

  • Each monthly XLSX data-row TOTAL PRICE cell is a formula whose business meaning is REAL PRICE × NIGHTS × NO_OF_ROOMS (current layout example: =R2*C2*G2).

  • A stored database total_price may be used for integrity checking, but it does not replace the required formula in the exported workbook.

  • Monthly business/guest rows remain derived from current Finance facts. PostgreSQL persists only publication identity, lineage, channel counts and artifact metadata.

  • The outbox event is marked published only after a report is active/superseded and both workbook/result artifacts are registered; replay of the same snapshot must not create a duplicate publication.

  • A published monthly version automatically appears in the open monthly list; the primary workflow has no manual list-refresh step.

  • Company-channel detail generation is allowed for any period in the selected current month and for historical months. A future report month is rejected so the system does not create an intentionally empty future workbook.

  • Company-channel C/O periods keep fixed report cutoffs: 01-10 uses the 10th, 11-20 uses the 20th and 21-month-end uses the selected month's natural month-end. The workbook uses the current committed Finance snapshot through that cutoff even when the calendar period has not ended; later-arriving facts require a rerun to be included.

  • The company-channel UI labels calendar status as 周期未结束 or 周期已结束. These labels describe whether the selected period has reached its Bangkok completion boundary; they are not generation permission states.

  • In a company-channel detail workbook, a Finance fact with no normalized Group Code remains visible as its own row; RES_COMMENT and Booking Room are blank, and this expected blank does not create a warning or duplicate highlight.

  • A Finance stay segment with a consistent nonblank Group Code keeps that Group Code and its normal aggregation. When no current accepted Booking room can be resolved, only Booking Room is blank; the lookup miss does not create an error or warning and does not block the company's workbook.

  • The company-report Booking allocation model consists of normalized Group Code, room type and quantity. A raw intake adapter may derive these fields from a source workbook, but raw workbook columns and normalized result dimensions are separate contracts; worksheet, physical row, artifact hash and parse version remain provenance.

  • A raw Booking workbook is recognized only on a worksheet containing exactly one approved Tour Code/Group Code header and exactly one approved hotel-detail header on the same row. Approved Tour Code labels are Tour Code, Group Code, Gourp Code, 团号, 团队代码 and Tour Code / 主团号; approved hotel-detail labels are โรงแรม, วางข้อมูลที่นี่ / 酒店明细 and Raw Hotel Detail / วางข้อมูลที่นี่ / 酒店明细. Header cells are Unicode/case/whitespace/punctuation-normalized before whole-cell exact comparison; substring, fuzzy, filename, month and worksheet-name matching are forbidden. Tour Codes are Unicode-normalized and all whitespace is removed before matching.

  • For repeated Tour Codes, the physically last source row replaces earlier rows. A final row with an explicit textual cancellation removes the Tour Code; cell color or other formatting alone never means cancellation.

  • Room extraction reads parenthesized hotel segments. A 【label】 token takes the following integer as quantity and defaults to one when no following integer exists. Multiple tokens become separate items even when they normalize to the same room type.

  • Numeric suffix variants of U-TWN and U-DBL normalize to U-TWN and U-DBL; 高级房TWN/高级房DBL normalize to TWN/DBL. Unknown bracket labels retain their raw text and parsed/default quantity as pending. Recognized unbracketed names such as 6+4, Family Suite, Junior Suite and Superior Garden also remain pending because the source omitted brackets. Surcharge, child-breakfast and guide-room tokens are not guest-room allocations.

  • Pending items do not contribute accepted Booking room quantity. Automatic and manual rows are both editable and deletable; activation requires zero pending items and at least one confirmed item. Re-extraction rebuilds the review draft from source and intentionally discards draft-only edits/deletions.

  • The review UI pages at 50 records. A delete request contains 1-50 unique item IDs and is all-or-nothing: every item must still be undeleted, belong to the same reviewing draft and be deletable, otherwise the transaction rolls back.

  • An open Booking review displays the draft artifact's validated browser-uploaded filename directly below Booking记录提取. Accepted historical-source readiness is not shown as provenance for draft extraction records.

  • Once accepted, a manually uploaded Booking workbook replaces the complete current source rather than appending silently to the previous workbook. Migrations 014/015 and the HTTP GET/POST/PATCH/DELETE adapter represent this boundary; the first real draft activation remains a controlled business acceptance action.

  • Booking normalizes the complete Group Code and globally aggregates repeated (Group Code, room type) rows by summed quantity. Worksheet, company/channel and stay dates are not current Booking join dimensions. This contract therefore requires one Group Code to identify one room allocation across those scopes; a different business reality requires a schema/view/report-join change, not merely extra unused Excel columns.

  • Contradictory Group Code source fields and invalid Finance dates, nights or price details remain strict company-report errors; the blank fallback applies only to absent or unresolved Booking enrichment.

Last Reviewed

2026-08-11

Direct data entry — 2026-09-18

2026-09-18 direct data: same whitelist, first room/date dedup, pricing, zero-price, nights and channel rules. Unresolved retained fields fail; only PRICE_UNMATCHED enters review. Notes use first nonempty after emoji cleanup; products display ordered codes; full multi-values retained in source; Trace blank. Source immutability and manual-price hash binding extend to JSON. See ADR-007.