feat: add daily manual price review workflow

This commit is contained in:
Wyndham ARR
2026-08-06 22:40:18 +08:00
parent aae3d8e1db
commit ca3e8e18fa
77 changed files with 7750 additions and 602 deletions

View File

@@ -11,10 +11,11 @@
7. Compute integer `NIGHTS = DEPARTURE - ARRIVAL`. Zero is legal; negative is invalid.
8. Validate the complete fixed price table, then apply the approved zero-price exception or exact three-key match. Classify unmatched candidates as `price_unmatched`.
9. Assign `channel_key` and conditional `kb_amount` as row facts.
10. Generate the 19-column daily XLSX, `result.json`, and path-free `structured-result.json` from the same in-memory records.
11. Independently replay the XML, rules, prices, routing, workbook, artifacts, outcomes, and structured records before reporting success.
10. If all actionable errors are `PRICE_UNMATCHED`, emit `review_required`: exact fixed-price rows become controlled `candidate` rows, unmatched rows stay explicit, issues are grouped by normalized company, rate code and Opera price, and no XLSX is made.
11. Otherwise generate the 19-column daily XLSX, `result.json`, and path-free `structured-result.json` from the same in-memory records.
12. Independently replay XML, rules, prices, routing, workbook (when present), artifacts, outcomes, and structured records before reporting a final result.
Any row-level validation or price error fails the formal invocation. On failure, already excluded, duplicate, or price-unmatched outcomes remain explicit. Other candidates that did not reach a validated result become `validation_failed` with `BATCH_NOT_VALIDATED`.
Only a non-empty error set composed entirely of `PRICE_UNMATCHED` may become `review_required`. Any XML, fixed-table, routing, output, structural, or mixed error remains a formal failure. On failure, already excluded, duplicate, or price-unmatched outcomes remain explicit. Other candidates that did not reach a validated result become `validation_failed` with `BATCH_NOT_VALIDATED`.
## Rate-code whitelist
@@ -56,7 +57,8 @@ Use bundled `价格对照.xlsx` as a fixed, non-user-editable rule source.
- Every other retained row must exactly match normalized `COMPANY_NAME + RATE_CODE + EFFECTIVE_RATE_AMOUNT`.
- Write reference `总价` as static `REAL PRICE`.
- Write static `TOTAL PRICE = REAL PRICE * NO_OF_ROOMS * NIGHTS`.
- An unmatched candidate fails the entire invocation.
- An unmatched candidate normally requires review only when it is the sole actionable error family. The review artifact contains no price substitution.
- A final review replay may price only the exact unmatched keys listed in its frozen manifest. `real_price` is a non-negative two-decimal value (including `0.00`), uses `pricing_method = manual_review` and `MANUAL_PRICE_APPLIED`, and never changes the fixed table or any XML field.
## Channel facts

View File

@@ -3,97 +3,69 @@
"title": "ARR Opera daily processing result",
"type": "object",
"additionalProperties": false,
"required": [
"version",
"status",
"business_date",
"message",
"metrics",
"outputs",
"errors"
],
"required": ["version", "status", "business_date", "message", "metrics", "outputs", "errors"],
"properties": {
"version": { "type": "string", "const": "3.0" },
"status": { "type": "string", "enum": ["success", "failed"] },
"version": { "type": "string", "const": "4.0" },
"status": { "type": "string", "enum": ["success", "review_required", "failed"] },
"business_date": { "type": ["string", "null"], "format": "date" },
"message": { "type": "string" },
"message": { "type": "string", "minLength": 1 },
"metrics": {
"type": "object",
"additionalProperties": false,
"required": [
"source_rows",
"removed_by_rate_code",
"removed_as_duplicates",
"output_rows",
"channels"
],
"required": ["source_rows", "removed_by_rate_code", "removed_as_duplicates", "output_rows", "candidate_rows", "review_required_rows", "review_issue_count", "channels"],
"properties": {
"source_rows": { "type": "integer", "minimum": 0 },
"removed_by_rate_code": { "type": "integer", "minimum": 0 },
"removed_as_duplicates": { "type": "integer", "minimum": 0 },
"output_rows": { "type": "integer", "minimum": 0 },
"channels": {
"type": "array",
"items": { "$ref": "#/$defs/channel" }
}
"candidate_rows": { "type": "integer", "minimum": 0 },
"review_required_rows": { "type": "integer", "minimum": 0 },
"review_issue_count": { "type": "integer", "minimum": 0 },
"channels": { "type": "array", "items": { "$ref": "#/$defs/channel" } }
}
},
"outputs": {
"type": "object",
"additionalProperties": false,
"required": [
"daily_report",
"structured_result",
"exception_report"
],
"required": ["daily_report", "structured_result", "exception_report"],
"properties": {
"daily_report": {
"type": ["string", "null"],
"pattern": "^[^/\\\\]+\\.xlsx$"
},
"structured_result": {
"type": ["string", "null"],
"pattern": "^[^/\\\\]+\\.json$"
},
"exception_report": {
"type": ["string", "null"],
"pattern": "^[^/\\\\]+\\.xlsx$"
}
"daily_report": { "type": ["string", "null"], "pattern": "^[^/\\\\]+\\.xlsx$" },
"structured_result": { "type": ["string", "null"], "pattern": "^[^/\\\\]+\\.json$" },
"exception_report": { "type": ["string", "null"], "pattern": "^[^/\\\\]+\\.xlsx$" }
}
},
"errors": {
"type": "array",
"items": { "$ref": "#/$defs/error" }
}
"errors": { "type": "array", "items": { "$ref": "#/$defs/error" } }
},
"allOf": [
{
"if": {
"properties": { "status": { "const": "success" } },
"required": ["status"]
},
"if": { "properties": { "status": { "const": "success" } }, "required": ["status"] },
"then": {
"properties": {
"business_date": { "type": "string", "format": "date" },
"outputs": {
"properties": {
"daily_report": { "type": "string" },
"structured_result": { "type": "string" },
"exception_report": { "type": "null" }
}
},
"errors": { "maxItems": 0 }
"errors": { "maxItems": 0 },
"metrics": { "properties": { "candidate_rows": { "const": 0 }, "review_required_rows": { "const": 0 }, "review_issue_count": { "const": 0 } } },
"outputs": { "properties": { "daily_report": { "type": "string" }, "structured_result": { "type": "string" }, "exception_report": { "type": "null" } } }
}
},
"else": {
}
},
{
"if": { "properties": { "status": { "const": "review_required" } }, "required": ["status"] },
"then": {
"properties": {
"outputs": {
"properties": {
"daily_report": { "type": "null" },
"exception_report": { "type": "string" }
}
},
"errors": { "minItems": 1 }
"business_date": { "type": "string", "format": "date" },
"errors": { "minItems": 1 },
"metrics": { "properties": { "output_rows": { "const": 0 }, "review_required_rows": { "minimum": 1 }, "review_issue_count": { "minimum": 1 }, "channels": { "maxItems": 0 } } },
"outputs": { "properties": { "daily_report": { "type": "null" }, "structured_result": { "type": "string" }, "exception_report": { "type": "null" } } }
}
}
},
{
"if": { "properties": { "status": { "const": "failed" } }, "required": ["status"] },
"then": {
"properties": {
"errors": { "minItems": 1 },
"metrics": { "properties": { "output_rows": { "const": 0 }, "candidate_rows": { "const": 0 }, "review_issue_count": { "const": 0 }, "channels": { "maxItems": 0 } } },
"outputs": { "properties": { "daily_report": { "type": "null" }, "exception_report": { "type": "string" } } }
}
}
}
@@ -103,24 +75,12 @@
"type": "object",
"additionalProperties": false,
"required": ["worksheet", "rows"],
"properties": {
"worksheet": { "type": "string", "minLength": 1 },
"rows": { "type": "integer", "minimum": 0 }
}
"properties": { "worksheet": { "type": "string", "minLength": 1 }, "rows": { "type": "integer", "minimum": 0 } }
},
"error": {
"type": "object",
"additionalProperties": false,
"required": [
"code",
"stage",
"source_location",
"company_name",
"rate_code",
"effective_rate_amount",
"confirmation_no",
"message"
],
"required": ["code", "stage", "source_location", "company_name", "rate_code", "effective_rate_amount", "confirmation_no", "message"],
"properties": {
"code": { "type": "string", "minLength": 1 },
"stage": { "type": "string", "minLength": 1 },

View File

@@ -4,7 +4,7 @@
Treat one XML invocation as an atomic file-processing unit.
On any input, XML, price, routing, write, structured-completeness, or independent-validation error:
On any input, XML, price, routing, write, structured-completeness, or independent-validation error that is not a pure `PRICE_UNMATCHED` review result:
- do not return a formal daily workbook;
- delete candidate daily/structured files from the failed attempt;
@@ -25,6 +25,8 @@ The failed structured payload still preserves every parsed reservation and its f
| `3` | Invocation/input-contract failure |
| `4` | Unexpected dependency/internal failure |
`review_required` is a successful technical exit (`0`), but not a successful business commit: it writes only the two JSON artifacts and has no daily/exception workbook. It is allowed only when `PRICE_UNMATCHED` is the complete actionable error set.
## Exception workbook
Columns:
@@ -45,15 +47,16 @@ Write one row per independently actionable error. Leave unavailable fields blank
## Success/failure invariants
- `status` is `success` or `failed`.
- `status` is `success`, `review_required`, or `failed`.
- Output references in `result.json` are basenames, never paths.
- Success lists daily and structured files, lists no exception file, and has no errors.
- Failure lists no daily file, lists an exception file, and has at least one error.
- Review lists no daily or exception file, has only `PRICE_UNMATCHED` errors, candidate/review issue counts, and `activation_eligible: false`.
- `metrics.channels` is a deterministic array of `{ "worksheet": string, "rows": integer }`.
- Structured success requires exact artifact metadata, balanced five-outcome counts, no `validation_failed`/`price_unmatched`, and `activation_eligible: true`.
- Structured success requires exact artifact metadata, balanced six-outcome counts, no `candidate`/`validation_failed`/`price_unmatched`, and `activation_eligible: true`.
- Structured failure has `output_rows = 0`, no channel metrics, no daily artifact, a non-empty error array, and `activation_eligible: false`.
- Never place guest details in the public `message`.
## Database boundary
This Skill never executes database DDL or DML. ARR may start its transaction only after process exit `0`, Schema validation, and independent re-hashing. ARR activates a new same-day version only as the last step of a successful transaction; any failure must roll back and leave the previous current version unchanged.
This Skill never executes database DDL or DML. ARR may record a `review_required` receipt after its JSON/schema validation, but it may start a Finance transaction only after final success, independent re-hashing and replay. ARR activates a new same-day version only as the last step of that transaction; any final failure must roll back and leave the previous current version unchanged.

View File

@@ -0,0 +1,41 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "ARR frozen daily manual-price override manifest",
"type": "object",
"additionalProperties": false,
"required": ["review_version", "review_case_id", "job_id", "source_sha256", "business_date", "processor_version", "rule_set_sha256", "issues", "overrides"],
"properties": {
"review_version": { "const": "1.0" },
"review_case_id": { "type": "string", "pattern": "^dailyreview-[0-9a-f]{32}$" },
"job_id": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$" },
"source_sha256": { "$ref": "#/$defs/sha256" },
"business_date": { "type": "string", "format": "date" },
"processor_version": { "type": "string", "const": "4.0.0" },
"rule_set_sha256": { "$ref": "#/$defs/sha256" },
"issues": { "type": "array", "minItems": 1, "items": { "$ref": "#/$defs/key" } },
"overrides": { "type": "array", "items": { "$ref": "#/$defs/override" } }
},
"$defs": {
"sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
"amount": { "type": "string", "pattern": "^(?:0|[1-9][0-9]*)(?:\\.[0-9]+)?$" },
"key": {
"type": "object", "additionalProperties": false,
"required": ["company_key", "rate_code", "effective_rate_amount"],
"properties": {
"company_key": { "type": "string", "minLength": 1 },
"rate_code": { "type": "string", "pattern": "^[A-Z0-9]+$" },
"effective_rate_amount": { "$ref": "#/$defs/amount" }
}
},
"override": {
"type": "object", "additionalProperties": false,
"required": ["company_key", "rate_code", "effective_rate_amount", "real_price"],
"properties": {
"company_key": { "type": "string", "minLength": 1 },
"rate_code": { "type": "string", "pattern": "^[A-Z0-9]+$" },
"effective_rate_amount": { "$ref": "#/$defs/amount" },
"real_price": { "type": "string", "pattern": "^(?:0|[1-9][0-9]{0,15})\\.[0-9]{2}$" }
}
}
}
}

View File

@@ -2,17 +2,17 @@
## Purpose
`structured-result.json` version `3.0` is the daily fact payload consumed by the trusted ARR adapter. It contains every XML source reservation, including filtered, duplicate, invalid, and unmatched rows.
`structured-result.json` version `4.0` is the daily fact/review payload consumed by the trusted ARR adapter. It contains every XML source reservation, including filtered, duplicate, invalid, candidate and unmatched rows. Historical v3 artifacts remain ARR read-compatible only; they do not gain manual-review behavior.
`result.json` is the Agent/front-end run result. Do not add database records to it. Do not reconstruct database rows from the XLSX.
`result.json` is the ARR/front-end run result. Do not add database records to it. Do not reconstruct database rows from the XLSX.
## Transport boundary
- `fetch_oss_file` and its OSS credentials belong to the Agent runtime, not this Skill.
- The Agent passes the fetched local XML path into the processor.
- Object storage materialization and its credentials belong to the ARR runtime, not this Skill.
- The runtime passes one already-fetched local XML path into the processor.
- ARR already knows the job/source-file identity from the upload context and binds that identity to this payload after comparing the XML hash.
- Structured artifact objects contain no local absolute path, OSS key, signed URL, AccessKey, or database credential.
- Agent-local paths are ephemeral orchestration data and must not be persisted as business facts.
- Runtime-local paths are ephemeral orchestration data and must not be persisted as business facts.
## Batch fields
@@ -25,8 +25,10 @@ The payload includes:
- `source_rows`
- `removed_by_rate_code`
- `removed_as_duplicates`
- `output_rows`
- five-outcome reconciliation
- `output_rows`, `candidate_rows`, `review_required_rows`, and `review_issue_count`
- six-outcome reconciliation
- grouped, privacy-minimized `review_issues` with fixed-table candidate-price comparisons
- `review_case_id`, `manual_override_sha256`, and `manually_priced_rows` on final manual replay only
- channel counts
- path-free XML/daily/result/exception artifact metadata
- every XML source record in original order
@@ -41,12 +43,13 @@ The structured file does not hash itself, avoiding self-hash recursion.
Allowed outcomes:
- `retained`
- `candidate`
- `excluded_rate_code`
- `duplicate`
- `validation_failed`
- `price_unmatched`
Duplicates point to an earlier `source_sequence`. `decision_codes` explain deterministic choices.
Duplicates point to an earlier `source_sequence`. `decision_codes` explain deterministic choices. A final replay changes only approved missing-key rows to `retained` with `pricing_method: manual_review` and `MANUAL_PRICE_APPLIED`; candidate rows never enter Finance facts.
For direct XML:
@@ -77,6 +80,6 @@ It may then expose `booking.booking_source_rows.hotel_raw` as the original booki
## Activation boundary
`activation_eligible: true` means only that the deterministic file pipeline passed. It does not mean database commit succeeded.
`activation_eligible: true` means only that the deterministic final file pipeline passed. It does not mean database commit succeeded. `review_required` is false and has no daily/report artifact.
ARR must revalidate the Schema and hashes, write file/version/record/channel/lookup rows in one transaction, and switch the current daily version last. A rerun of the same business date creates a new immutable version; only the successful committed version becomes current.
ARR must revalidate Schema, hashes and the independent replay before it writes file/version/record/channel/lookup rows in one transaction and switches the current daily version last. Review receipt writes only a case/items/events audit record. A frozen manual replay creates the first Finance version and one commit event only after that final validation succeeds.

View File

@@ -1,50 +1,40 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://arr.local/schemas/opera-daily-structured-result-v3.json",
"$id": "https://arr.local/schemas/opera-daily-structured-result-v4.json",
"title": "ARR Opera daily finance-ready structured result",
"type": "object",
"additionalProperties": false,
"required": [
"result_schema_version",
"status",
"activation_eligible",
"ingestion_mode",
"business_date",
"processor_version",
"rule_set_sha256",
"source_rows",
"removed_by_rate_code",
"removed_as_duplicates",
"output_rows",
"outcome_counts",
"channels",
"artifacts",
"records",
"errors"
"result_schema_version", "status", "activation_eligible", "ingestion_mode", "business_date",
"processor_version", "rule_set_sha256", "source_rows", "removed_by_rate_code",
"removed_as_duplicates", "output_rows", "outcome_counts", "candidate_rows",
"review_required_rows", "review_issue_count", "review_issues", "review_case_id",
"manual_override_sha256", "manually_priced_rows", "channels", "artifacts", "records", "errors"
],
"properties": {
"result_schema_version": { "type": "string", "const": "3.0" },
"status": { "type": "string", "enum": ["success", "failed"] },
"result_schema_version": { "type": "string", "const": "4.0" },
"status": { "type": "string", "enum": ["success", "review_required", "failed"] },
"activation_eligible": { "type": "boolean" },
"ingestion_mode": { "type": "string", "const": "opera_xml" },
"business_date": { "type": ["string", "null"], "format": "date" },
"processor_version": { "type": "string", "minLength": 1 },
"processor_version": { "type": "string", "const": "4.0.0" },
"rule_set_sha256": { "$ref": "#/$defs/sha256" },
"source_rows": { "type": "integer", "minimum": 0 },
"removed_by_rate_code": { "type": "integer", "minimum": 0 },
"removed_as_duplicates": { "type": "integer", "minimum": 0 },
"output_rows": { "type": "integer", "minimum": 0 },
"candidate_rows": { "type": "integer", "minimum": 0 },
"review_required_rows": { "type": "integer", "minimum": 0 },
"review_issue_count": { "type": "integer", "minimum": 0 },
"review_issues": { "type": "array", "items": { "$ref": "#/$defs/reviewIssue" } },
"review_case_id": { "type": ["string", "null"], "pattern": "^dailyreview-[0-9a-f]{32}$" },
"manual_override_sha256": { "oneOf": [{ "$ref": "#/$defs/sha256" }, { "type": "null" }] },
"manually_priced_rows": { "type": "integer", "minimum": 0 },
"outcome_counts": {
"type": "object",
"additionalProperties": false,
"required": [
"duplicate",
"excluded_rate_code",
"price_unmatched",
"retained",
"validation_failed"
],
"type": "object", "additionalProperties": false,
"required": ["candidate", "duplicate", "excluded_rate_code", "price_unmatched", "retained", "validation_failed"],
"properties": {
"candidate": { "type": "integer", "minimum": 0 },
"duplicate": { "type": "integer", "minimum": 0 },
"excluded_rate_code": { "type": "integer", "minimum": 0 },
"price_unmatched": { "type": "integer", "minimum": 0 },
@@ -52,275 +42,155 @@
"validation_failed": { "type": "integer", "minimum": 0 }
}
},
"channels": {
"type": "array",
"items": { "$ref": "#/$defs/channel" }
},
"channels": { "type": "array", "items": { "$ref": "#/$defs/channel" } },
"artifacts": {
"type": "object",
"additionalProperties": false,
"required": [
"source_xml",
"daily_report",
"result_json",
"exception_report"
],
"type": "object", "additionalProperties": false,
"required": ["source_xml", "daily_report", "result_json", "exception_report", "manual_override_json"],
"properties": {
"source_xml": { "$ref": "#/$defs/nullableArtifact" },
"daily_report": { "$ref": "#/$defs/nullableArtifact" },
"result_json": { "$ref": "#/$defs/nullableArtifact" },
"exception_report": { "$ref": "#/$defs/nullableArtifact" }
"exception_report": { "$ref": "#/$defs/nullableArtifact" },
"manual_override_json": { "$ref": "#/$defs/nullableArtifact" }
}
},
"records": {
"type": "array",
"items": { "$ref": "#/$defs/record" }
},
"errors": {
"type": "array",
"items": { "$ref": "#/$defs/error" }
}
"records": { "type": "array", "items": { "$ref": "#/$defs/record" } },
"errors": { "type": "array", "items": { "$ref": "#/$defs/error" } }
},
"allOf": [
{
"if": {
"properties": { "status": { "const": "success" } },
"required": ["status"]
},
"if": { "properties": { "status": { "const": "success" } }, "required": ["status"] },
"then": {
"properties": {
"activation_eligible": { "const": true },
"business_date": { "type": "string", "format": "date" },
"errors": { "maxItems": 0 },
"artifacts": {
"properties": {
"source_xml": { "$ref": "#/$defs/artifact" },
"daily_report": { "$ref": "#/$defs/artifact" },
"result_json": { "$ref": "#/$defs/artifact" },
"exception_report": { "type": "null" }
}
}
"activation_eligible": { "const": true }, "business_date": { "type": "string", "format": "date" },
"errors": { "maxItems": 0 }, "candidate_rows": { "const": 0 }, "review_required_rows": { "const": 0 },
"review_issue_count": { "const": 0 }, "review_issues": { "maxItems": 0 },
"artifacts": { "properties": {
"source_xml": { "$ref": "#/$defs/artifact" }, "daily_report": { "$ref": "#/$defs/artifact" },
"result_json": { "$ref": "#/$defs/artifact" }, "exception_report": { "type": "null" }
} }
}
},
"else": {
}
},
{
"if": { "properties": { "status": { "const": "review_required" } }, "required": ["status"] },
"then": {
"properties": {
"activation_eligible": { "const": false },
"output_rows": { "const": 0 },
"channels": { "maxItems": 0 },
"activation_eligible": { "const": false }, "business_date": { "type": "string", "format": "date" },
"output_rows": { "const": 0 }, "review_required_rows": { "minimum": 1 }, "review_issue_count": { "minimum": 1 },
"errors": { "minItems": 1 }, "channels": { "maxItems": 0 }, "review_case_id": { "type": "null" },
"manual_override_sha256": { "type": "null" }, "manually_priced_rows": { "const": 0 },
"artifacts": { "properties": {
"source_xml": { "$ref": "#/$defs/artifact" }, "result_json": { "$ref": "#/$defs/artifact" },
"daily_report": { "type": "null" }, "exception_report": { "type": "null" }, "manual_override_json": { "type": "null" }
} }
}
}
},
{
"if": { "properties": { "status": { "const": "failed" } }, "required": ["status"] },
"then": {
"properties": {
"activation_eligible": { "const": false }, "output_rows": { "const": 0 }, "candidate_rows": { "const": 0 },
"review_issue_count": { "const": 0 }, "review_issues": { "maxItems": 0 }, "review_case_id": { "type": "null" },
"manual_override_sha256": { "type": "null" }, "manually_priced_rows": { "const": 0 }, "channels": { "maxItems": 0 },
"errors": { "minItems": 1 },
"artifacts": {
"properties": {
"daily_report": { "type": "null" },
"exception_report": { "$ref": "#/$defs/artifact" }
}
}
"artifacts": { "properties": {
"daily_report": { "type": "null" }, "exception_report": { "$ref": "#/$defs/artifact" },
"manual_override_json": { "type": "null" }
} }
}
}
}
],
"$defs": {
"sha256": {
"type": "string",
"pattern": "^[0-9a-f]{64}$"
},
"sha256": { "type": "string", "pattern": "^[0-9a-f]{64}$" },
"artifact": {
"type": "object",
"additionalProperties": false,
"required": [
"file_kind",
"original_filename",
"sha256",
"byte_size",
"mime_type"
],
"type": "object", "additionalProperties": false,
"required": ["file_kind", "original_filename", "sha256", "byte_size", "mime_type"],
"properties": {
"file_kind": {
"type": "string",
"enum": [
"opera_xml",
"daily_xlsx",
"result_json",
"exception_xlsx"
]
},
"file_kind": { "type": "string", "enum": ["opera_xml", "daily_xlsx", "result_json", "exception_xlsx", "manual_override_json"] },
"original_filename": { "type": "string", "minLength": 1 },
"sha256": { "$ref": "#/$defs/sha256" },
"byte_size": { "type": "integer", "minimum": 0 },
"sha256": { "$ref": "#/$defs/sha256" }, "byte_size": { "type": "integer", "minimum": 0 },
"mime_type": { "type": "string", "minLength": 1 }
}
},
"nullableArtifact": {
"oneOf": [
{ "$ref": "#/$defs/artifact" },
{ "type": "null" }
]
},
"nullableArtifact": { "oneOf": [{ "$ref": "#/$defs/artifact" }, { "type": "null" }] },
"channel": {
"type": "object",
"additionalProperties": false,
"required": ["worksheet", "rows"],
"type": "object", "additionalProperties": false, "required": ["worksheet", "rows"],
"properties": { "worksheet": { "type": "string", "minLength": 1 }, "rows": { "type": "integer", "minimum": 0 } }
},
"reviewIssue": {
"type": "object", "additionalProperties": false,
"required": ["company_key", "rate_code", "effective_rate_amount", "candidate_prices", "affected_records", "affected_rooms", "affected_room_nights"],
"properties": {
"worksheet": { "type": "string", "minLength": 1 },
"rows": { "type": "integer", "minimum": 0 }
"company_key": { "type": "string", "minLength": 1 }, "rate_code": { "type": "string", "minLength": 1 },
"effective_rate_amount": { "type": "number", "minimum": 0 },
"candidate_prices": { "type": "array", "items": { "$ref": "#/$defs/priceCandidate" } },
"affected_records": { "type": "integer", "minimum": 1 }, "affected_rooms": { "type": "integer", "minimum": 1 },
"affected_room_nights": { "type": "integer", "minimum": 0 }
}
},
"priceCandidate": {
"type": "object", "additionalProperties": false, "required": ["effective_rate_amount", "real_price"],
"properties": { "effective_rate_amount": { "type": "number", "minimum": 0 }, "real_price": { "type": "number", "minimum": 0 } }
},
"record": {
"type": "object",
"additionalProperties": false,
"type": "object", "additionalProperties": false,
"required": [
"source_sequence",
"source_location",
"source_worksheet",
"source_row_no",
"outcome",
"decision_codes",
"duplicate_of_source_sequence",
"adults",
"children",
"block_code",
"no_of_rooms",
"company_name",
"company_key",
"confirmation_no",
"disp_room_no",
"effective_rate_amount",
"full_name",
"res_comment",
"group_code_key",
"booking_source_match_status",
"trace_text",
"products",
"rate_code",
"normalized_rate_code",
"room_category_label",
"arrival",
"departure",
"nights",
"real_price",
"total_price",
"kb_amount",
"channel_key",
"pricing_method"
"source_sequence", "source_location", "source_worksheet", "source_row_no", "outcome", "decision_codes",
"duplicate_of_source_sequence", "adults", "children", "block_code", "no_of_rooms", "company_name", "company_key",
"confirmation_no", "disp_room_no", "effective_rate_amount", "full_name", "res_comment", "group_code_key",
"booking_source_match_status", "trace_text", "products", "rate_code", "normalized_rate_code", "room_category_label",
"arrival", "departure", "nights", "real_price", "total_price", "kb_amount", "channel_key", "pricing_method"
],
"properties": {
"source_sequence": { "type": "integer", "minimum": 1 },
"source_location": { "type": "string", "minLength": 1 },
"source_worksheet": { "type": "null" },
"source_row_no": { "type": "null" },
"outcome": {
"type": "string",
"enum": [
"retained",
"excluded_rate_code",
"duplicate",
"validation_failed",
"price_unmatched"
]
},
"decision_codes": {
"type": "array",
"uniqueItems": true,
"items": { "type": "string", "minLength": 1 }
},
"duplicate_of_source_sequence": {
"type": ["integer", "null"],
"minimum": 1
},
"adults": { "type": ["integer", "null"] },
"children": { "type": ["integer", "null"] },
"block_code": { "type": "string" },
"no_of_rooms": { "type": ["integer", "null"] },
"company_name": { "type": "string" },
"company_key": { "type": ["string", "null"], "minLength": 1 },
"confirmation_no": { "type": "string" },
"disp_room_no": { "type": "string" },
"effective_rate_amount": { "type": ["number", "null"] },
"full_name": { "type": "string" },
"res_comment": { "type": "string" },
"source_sequence": { "type": "integer", "minimum": 1 }, "source_location": { "type": "string", "minLength": 1 },
"source_worksheet": { "type": "null" }, "source_row_no": { "type": "null" },
"outcome": { "type": "string", "enum": ["retained", "candidate", "excluded_rate_code", "duplicate", "validation_failed", "price_unmatched"] },
"decision_codes": { "type": "array", "uniqueItems": true, "items": { "type": "string", "minLength": 1 } },
"duplicate_of_source_sequence": { "type": ["integer", "null"], "minimum": 1 },
"adults": { "type": ["integer", "null"] }, "children": { "type": ["integer", "null"] }, "block_code": { "type": "string" },
"no_of_rooms": { "type": ["integer", "null"] }, "company_name": { "type": "string" },
"company_key": { "type": ["string", "null"], "minLength": 1 }, "confirmation_no": { "type": "string" },
"disp_room_no": { "type": "string" }, "effective_rate_amount": { "type": ["number", "null"] },
"full_name": { "type": "string" }, "res_comment": { "type": "string" },
"group_code_key": { "type": ["string", "null"], "minLength": 1 },
"booking_source_match_status": {
"type": "string",
"enum": ["missing_group_code", "not_checked"]
},
"trace_text": { "type": "string" },
"products": { "type": "string" },
"rate_code": { "type": "string" },
"normalized_rate_code": { "type": ["string", "null"], "minLength": 1 },
"room_category_label": { "type": "string" },
"arrival": { "type": ["string", "null"], "format": "date" },
"departure": { "type": ["string", "null"], "format": "date" },
"nights": { "type": ["integer", "null"] },
"real_price": { "type": ["number", "null"] },
"total_price": { "type": ["number", "null"] },
"kb_amount": { "type": ["number", "null"] },
"booking_source_match_status": { "type": "string", "enum": ["missing_group_code", "not_checked"] },
"trace_text": { "type": "string" }, "products": { "type": "string" }, "rate_code": { "type": "string" },
"normalized_rate_code": { "type": ["string", "null"], "minLength": 1 }, "room_category_label": { "type": "string" },
"arrival": { "type": ["string", "null"], "format": "date" }, "departure": { "type": ["string", "null"], "format": "date" },
"nights": { "type": ["integer", "null"] }, "real_price": { "type": ["number", "null"] },
"total_price": { "type": ["number", "null"] }, "kb_amount": { "type": ["number", "null"] },
"channel_key": { "type": ["string", "null"], "minLength": 1 },
"pricing_method": {
"type": ["string", "null"],
"enum": ["zero_price_exception", "price_reference_exact", null]
}
"pricing_method": { "type": ["string", "null"], "enum": ["zero_price_exception", "price_reference_exact", "manual_review", null] }
},
"allOf": [
{
"if": {
"properties": { "outcome": { "const": "duplicate" } },
"required": ["outcome"]
},
"then": {
"properties": {
"duplicate_of_source_sequence": {
"type": "integer",
"minimum": 1
}
}
},
"else": {
"properties": {
"duplicate_of_source_sequence": { "type": "null" }
}
}
"if": { "properties": { "outcome": { "const": "duplicate" } }, "required": ["outcome"] },
"then": { "properties": { "duplicate_of_source_sequence": { "type": "integer", "minimum": 1 } } },
"else": { "properties": { "duplicate_of_source_sequence": { "type": "null" } } }
},
{
"if": {
"properties": { "outcome": { "const": "retained" } },
"required": ["outcome"]
},
"then": {
"properties": {
"adults": { "type": "integer", "minimum": 0 },
"children": { "type": "integer", "minimum": 0 },
"no_of_rooms": { "type": "integer", "minimum": 1 },
"effective_rate_amount": { "type": "number", "minimum": 0 },
"nights": { "type": "integer", "minimum": 0 },
"real_price": { "type": "number", "minimum": 0 },
"total_price": { "type": "number", "minimum": 0 },
"kb_amount": { "type": ["number", "null"], "minimum": 0 }
}
}
"if": { "properties": { "outcome": { "enum": ["retained", "candidate"] } }, "required": ["outcome"] },
"then": { "properties": {
"adults": { "type": "integer", "minimum": 0 }, "children": { "type": "integer", "minimum": 0 },
"no_of_rooms": { "type": "integer", "minimum": 1 }, "effective_rate_amount": { "type": "number", "minimum": 0 },
"nights": { "type": "integer", "minimum": 0 }, "real_price": { "type": "number", "minimum": 0 },
"total_price": { "type": "number", "minimum": 0 }, "kb_amount": { "type": ["number", "null"], "minimum": 0 },
"channel_key": { "type": "string", "minLength": 1 }, "pricing_method": { "type": "string", "enum": ["zero_price_exception", "price_reference_exact", "manual_review"] }
} }
}
]
},
"error": {
"type": "object",
"additionalProperties": false,
"required": [
"code",
"stage",
"source_location",
"company_name",
"rate_code",
"effective_rate_amount",
"confirmation_no",
"message"
],
"type": "object", "additionalProperties": false,
"required": ["code", "stage", "source_location", "company_name", "rate_code", "effective_rate_amount", "confirmation_no", "message"],
"properties": {
"code": { "type": "string", "minLength": 1 },
"stage": { "type": "string", "minLength": 1 },
"source_location": { "type": ["string", "null"] },
"company_name": { "type": ["string", "null"] },
"rate_code": { "type": ["string", "null"] },
"effective_rate_amount": { "type": ["number", "null"] },
"confirmation_no": { "type": ["string", "null"] },
"message": { "type": "string", "minLength": 1 }
"code": { "type": "string", "minLength": 1 }, "stage": { "type": "string", "minLength": 1 },
"source_location": { "type": ["string", "null"] }, "company_name": { "type": ["string", "null"] },
"rate_code": { "type": ["string", "null"] }, "effective_rate_amount": { "type": ["number", "null"] },
"confirmation_no": { "type": ["string", "null"] }, "message": { "type": "string", "minLength": 1 }
}
}
}