Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Package creation

Description / Background

Package creation combines partner self-service package submission, admin review, package editing, and package-list navigation improvements for All You Can Eat (AYCE) and Party Pack (PP) packages.

The feature has three source layers:

  • AYCE self-service creation, AI triage, admin approval, partner edit review, and 13-language translation.
  • Party Pack self-service creation using the shared submission and approval workflow with Party Pack-specific pricing and validation rules.
  • Package creation v2 navigation and form changes, including Add-on listing, section ordering, schedule defaults, cover-image copy, and payment-rule snapshots.

Backend implementation is represented by merged PR #8001. It introduces the package submission and draft-version workflow, validation and normalization services, admin review endpoints, notification workers, serializer fields, and frontend-facing admin screens.

Objectives

  • Allow restaurant partners to create AYCE and Party Pack packages from Partner Portal.
  • Validate package data, pricing, schedules, menus, payment options, and package-type rules before persistence.
  • Create a review submission for every new partner package on Admin Dashboard.
  • Route partner package edits through draft versions and admin review.
  • Classify safe and significant package edits for review and application.
  • Allow admins to review pending submissions, approve, reject, or edit and approve submissions.
  • Notify admins about new submissions and partners about approval, rejection, or admin changes.
  • Expose submission status, rejection reason, edit capability, and package data required by frontend screens.
  • Support AYCE and Party Pack package-specific creation forms and pricing models.
  • Snapshot payment rules at package creation so restaurant configuration changes do not mutate existing package behavior.

Scope

In scope

  • AYCE package creation.
  • Party Pack package creation.
  • Partner Portal package listing, creation, and update flows.
  • Package submission status: pending_review, approved, and rejected.
  • Package submission types: new_package and edit_request.
  • Draft versions for significant edits.
  • Admin pending-approval and submission-history screens.
  • Admin approval, rejection, and edit-and-approve flows.
  • Submission email notifications.
  • Package status filters and frontend serializer fields.
  • Package Creation v2 navigation and form layout requirements.
  • Package-level payment-rule snapshot requirements.

Out of scope or not confirmed by PR #8001

  • AI Prompt A, B, C, and D execution implementation.
  • 13-language translation worker implementation beyond existing translation integration points.
  • Bulk approval or rejection.
  • SLA breach notifications beyond SLA status calculation and display.
  • Final payment snapshot column name.
  • Final timezone policy for v2 start-date defaults.

Location

Partner Portal

  • AYCE creation: partner.hungryhub.com/packages/create/ayce
  • Party Pack creation: partner.hungryhub.com/packages/create/party-pack
  • All Packages: Partner Portal package listing.

Admin

  • Package submissions: /admin/package_submissions

How to find package creation

Partner package creation

  1. Open Partner Portal.
  2. Open Packages.
  3. Select Create Package.
  4. Select AYCE or Party Pack.
  5. Complete the package form.
  6. Save and confirm submission.

Partner package status

  1. Open Partner Portal.
  2. Open View All Packages.
  3. Use package status filters.
  4. Review Active, Active Pending Edit, Pending Review, Rejected, or Inactive status.

Admin package approval

  1. Open Admin Dashboard.
  2. Open Packages.
  3. Select Package Submissions.
  4. Review Pending Approval.
  5. Select Approve, Reject, or View.
  6. Use submission history to inspect approved or rejected submissions.

How to set Package on Partner Portal

  • Package navigation contains View All Packages and Create Package.
  • Create-page section order is:
    1. Package Basic Info
    2. Pricing
    3. Menu for package
    4. Bookable schedule and period
    5. Cover Image for Marketing
  • Period type defaults to On-going.
  • Start date defaults to today in the restaurant timezone when the timezone policy is applied.
  • Schedule label is All day (based on operating hours).
  • + Add Exception and + Add Schedule appear at the bottom of their respective sections.
  • Restaurant configuration changes do not change existing package setting.

Submission review rules

  • New partner packages create a new_package submission.
  • Partner edits create an edit_request submission when the package is eligible for editing.
  • A package cannot receive a second pending edit while one submission is already pending.
  • Admin-created packages cannot be edited from Partner Portal.
  • Rejected submissions remain immutable for the partner flow.
  • Admin approval publishes the restaurant package and applies a pending draft version when present.
  • Admin rejection requires a rejection reason.

Sequence Diagram / Flow

flowchart LR
  partner[Partner Portal] --> form[AYCE or Party Pack form]
  form --> sanitize[Package params sanitizer]
  sanitize --> validate[Package validator]
  validate --> create[Create package service]
  create --> package[Package and restaurant package]
  create --> submission[Pending package submission]
  submission --> admin_email[Admin notification worker]
  submission --> queue[Admin pending approval queue]
  queue --> review[Admin review]
  review --> approve[Approve or edit and approve]
  review --> reject[Reject with reason]
  approve --> draft[Apply pending draft version]
  draft --> publish[Activate and show package]
  approve --> partner_email[Partner approval notification]
  reject --> partner_reject[Partner rejection notification]
  partner --> update[Update active partner package]
  update --> detect[Package change detector]
  detect --> draft_request[Draft version and edit request]
  draft_request --> queue

ERD

erDiagram
  RESTAURANT ||--o{ RESTAURANT_PACKAGE : assigns
  RESTAURANT ||--o{ PACKAGE_SUBMISSION : receives
  STAFF ||--o{ PACKAGE_SUBMISSION : submits
  USER ||--o{ PACKAGE_SUBMISSION : reviews
  PACKAGE ||--o{ PACKAGE_SUBMISSION : has
  RESTAURANT_PACKAGE ||--o{ PACKAGE_SUBMISSION : references
  PACKAGE ||--o{ PACKAGE_DRAFT_VERSION : versions
  PACKAGE_SUBMISSION ||--o| PACKAGE_DRAFT_VERSION : contains

  PACKAGE_SUBMISSION {
    bigint id
    bigint package_id
    string package_type
    bigint restaurant_id
    bigint staff_id
    string submission_type
    string approval_status
    string package_category
    bigint reviewed_by_id
    datetime reviewed_at
    text rejection_reason
    text admin_notes
    datetime submitted_at
    bigint draft_version_id
    bigint restaurant_package_id
  }

  PACKAGE_DRAFT_VERSION {
    bigint id
    bigint package_id
    string package_type
    json previous_state
    json proposed_state
    json changed_fields
    string status
    datetime applied_at
  }

  RESTAURANT_PACKAGE {
    bigint id
    bigint restaurant_id
    bigint package_id
    boolean active
    boolean is_visible
  }

Backend Implementation

  • POST /api/partner/v1/restaurant_packages

    • Creates AYCE or Party Pack package through CreatePackageService.
    • Returns restaurant_package_id and submission_id on success.
  • PATCH /api/partner/v1/restaurant_packages/:id

    • Updates eligible partner-created active packages through UpdatePackageService.
    • Creates a draft version and edit-request submission.
  • GET /api/partner/v1/package_submissions/:id

    • Returns submission identity, review metadata, SLA status, and restaurant-package payload.
  • PATCH /api/partner/v1/package_submissions/:id/approve

    • Requires partner-portal-admin OAuth token with partner-admin scope.
    • Approves a submission with no package payload, with draft data, or with admin-edited package data.
  • PATCH /api/partner/v1/package_submissions/:id/reject

    • Requires rejection_reason.
    • Returns 400 when the reason is blank.
  • GET /api/partner/v1/restaurant_packages/payment_types

    • Returns payment types filtered by restaurant currency.
  • GET /admin/package_submissions

    • Renders pending submissions and approval history.
  • PATCH /admin/package_submissions/:id/approve

    • Approves from the Rails admin flow and redirects to the submissions page.
  • PATCH /admin/package_submissions/:id/reject

    • Rejects with a form-encoded reason and redirects to the submissions page.
  • Centralizes permitted package attributes and nested-attribute normalization.

  • Handles translation fallbacks, agendas, restaurant-package dates, pricing, kids prices, payment types, deletion flags, package-type fields, and currency conversion.

  • Converts Baht values to Satang when convert_currency: true.

  • Supports existing nested IDs and replacement of nested collections during update and approval.

  • Enforces commission, country, menu type, earn-point, reservation duration, advance-booking time, pricing model, currency, seating, kids-price eligibility, and inactive restaurant-package defaults.

  • Uses per_person for AYCE and per_pack for Party Pack.

  • Uses inventory maximum, restaurant largest table, or a fallback maximum for max seats.

  • Allows edits only for active packages created through Partner Portal.

  • Rejects admin-created packages.

  • Rejects packages with an existing pending submission.

  • Serializes the previous package state.

  • Detects changed fields.

  • Creates HhPackage::PackageDraftVersion and edit_request submission.

  • Enqueues the admin notification worker.

  • Admin::PackageSubmissionsController renders pending and history grids.

  • Pending grid displays SLA badge, submission date, package, type, recommendation, and actions.

  • History grid displays approval status, reviewer date, and expandable rejection reason.

  • Approval applies draft state, activates the restaurant package, and queues partner notification.

  • Rejection records reason and queues partner notification.

  • Partner Portal admin OAuth access token is generated for embedded review.

  • The review endpoint checks OAuth scope and restaurant ownership.

  • Added admin Package Submissions navigation.

  • Added pending submission count and approval-history UI.

  • Added SLA status badges and urgency ordering.

  • Added Approve, Reject, and View actions.

  • Added rejection confirmation modal and required reason validation.

  • Added embedded Partner Portal review iframe with OAuth token and restaurant scope.

  • Added review postMessage handling and automatic list refresh.

  • Added approved/rejected history badges and expandable rejection reasons.

  • Added package submission fields to serializer response: submission_status, submission_id, reject_reason, and can_edit.

  • Added frontend data fields for cover images, package menus, payment labels, charge policies, reservation duration, pricing, and kids policy.

  • Added package status filters, including pending_review, rejected, and active_pending_edit.

  • Pull request: https://github.com/hungryhub-team/hh-server/pull/8001

Frontend Implementation

Partner package creation form

  • Add AYCE and Party Pack package-type entry points.
  • Render common package fields for names, descriptions, images, menus, schedules, seating, pricing, payment, and charge policy.
  • Render AYCE-specific price tiers and kids-price controls.
  • Render Party Pack-specific dish/course count and per-pack pricing controls.
  • Apply bilingual input handling for English and Thai fields.
  • Apply image upload constraints and menu-image ordering.
  • Apply Accept All parent-child behavior for payment methods.
  • Show contextual prepayment controls and clear dependent values when payment mode changes.
  • Display default advance-booking, reservation-duration, seating, and commission behavior.
  • Submit package data and retain returned submission_id.

Package Creation v2 navigation and form updates

  • Remove Add-on from the left navigation.
  • Include Add-ons in All Packages.
  • Display Add-on in the Package Type column.
  • Hide Add-on edit actions.
  • Block direct Add-on edit routes with Add-ons cannot be edited yet.
  • Reorder create-page sections to Basic Info, Pricing, Menu, Schedule, and Cover Image.
  • Rename the cover section to Cover Image for Marketing (Optional).
  • Default schedule period to On-going.
  • Default start date to today under the selected timezone policy.
  • Rename the all-day checkbox to All day (based on operating hours).
  • Move + Add Exception and + Add Schedule to the bottom of their sections.
  • Remove Payment Info from Partner Portal.
  • Display payment behavior from the package-level snapshot after creation.

Package listing and status UI

  • Include Add-ons in All Packages.
  • Support status filters for Active, Active Pending Edit, Pending Review, Rejected, and Inactive.
  • Display rejection reason for rejected submissions.
  • Use can_edit to control partner edit actions.
  • Keep rejected partner submissions immutable.
  • Show pending review state after create or significant edit submission.

Mobile Implementation

N/A. Package creation and admin review scope described by the PRD and PR #8001 is Partner Portal and Admin web implementation.

PRD & Task

  • AYCE Package Creation PRD: https://app.clickup.com/9003122396/v/dc/8ca1fpw-30456/8ca1fpw-60936
  • Party Pack Package Creation PRD: https://app.clickup.com/9003122396/v/dc/8ca1fpw-30456/8ca1fpw-61396
  • Package Creation v2 PRD: https://app.clickup.com/9003122396/v/dc/8ca1fpw-30456/8ca1fpw-63616 Task:
  • Package submission backend implementation: https://github.com/hungryhub-team/hh-server/pull/8001
  • Draft override email reference: https://app.clickup.com/9003122396/v/dc/8ca1fpw-30456/8ca1fpw-61316

Design

  • AYCE and Party Pack Partner Portal design: https://www.figma.com/design/ymdLN2ZKzfI0oyX4kps2GQ/Partner-Portal-Desktop?node-id=17560-25083&t=vcnOJrUoX7l6eXQy-1
  • Party Pack Partner Portal design: https://www.figma.com/design/ymdLN2ZKzfI0oyX4kps2GQ/Partner-Portal-Desktop?node-id=17567-40098&t=2Snmy94oAl1r1qcE-1
  • Package Creation v2 design: https://www.figma.com/design/ymdLN2ZKzfI0oyX4kps2GQ/Partner-Portal-Desktop?node-id=18341-25362&m=dev

API Blueprint

MethodPathURLDescriptionPayload
POST/api/partner/v1/restaurant_packagesPartner API base URLCreate AYCE or Party Pack package and return submission ID.package_type, package, nested agendas, restaurant packages, package attributes, menus, pricing, payment types, and kids prices.
PATCH/api/partner/v1/restaurant_packages/:idPartner API base URLSubmit update for active partner-created package.Package fields and nested attributes. Creates draft version and edit request.
GET/api/partner/v1/package_submissions/:idPartner API base URLLoad submission and review payload.restaurant_id for scoped admin review.
PATCH/api/partner/v1/package_submissions/:id/approvePartner API base URLApprove submission with draft state or final admin edits.OAuth token, restaurant_id, optional package attributes.
PATCH/api/partner/v1/package_submissions/:id/rejectPartner API base URLReject submission and notify partner.OAuth token, restaurant_id, rejection_reason.
GET/api/partner/v1/restaurant_packages/payment_typesPartner API base URLReturn payment methods allowed for restaurant currency.Restaurant context.
GET/admin/package_submissionsAdmin applicationRender pending approvals and submission history.Admin session and optional pagination params.
PATCH/admin/package_submissions/:id/approveAdmin applicationApprove from Rails admin UI.Form submission with submission ID.
PATCH/admin/package_submissions/:id/rejectAdmin applicationReject from Rails admin UI.rejection_reason.

Approval and rejection statuses

  • 200: approval or rejection completed.
  • 201: package created and submitted.
  • 400: invalid package type, invalid payload, missing rejection reason, or invalid state transition.
  • 403: missing admin OAuth, invalid scope, or restaurant mismatch.
  • 404: submission or package not found.
  • 422: package validation failure during approval.
  • 500: unexpected approval or rejection failure.

New Query

Pending submissions

HhPackage::PackageSubmission.pending_review.by_urgency

Submission status for restaurant package

HhPackage::PackageSubmission.status_for_restaurant_package(restaurant_package)

Returns one of:

  • active
  • active_pending_edit
  • pending_review
  • rejected
  • inactive

Include inactive packages

Api::Partner::RestaurantPackagesFilter.new(restaurants, scope: 'all')

Package edit eligibility

package.active? &&
  HhPackage::PackageSubmission.package_created_by_partner?(package) &&
  !HhPackage::PackageSubmission.latest_for_package(package)&.pending_review?

DB Schema / Database Migration

hh_package_package_submissions

ColumnTypeDescription
package_idbigintPolymorphic package ID.
package_typevarchar(100)Polymorphic package type.
restaurant_idbigintRestaurant submitting or owning package.
staff_idbigintPartner staff submitter.
submission_typevarchar(20)new_package or edit_request.
approval_statusvarchar(20)pending_review, approved, or rejected.
package_categoryvarchar(20)ayce or pp.
reviewed_by_idbigintAdmin reviewer.
reviewed_atdatetimeReview completion time.
rejection_reasontextRequired for rejected submissions.
admin_notestextAdmin or AI recommendation notes.
submitted_atdatetimeSubmission timestamp.
draft_version_idbigintAssociated draft version.
restaurant_package_idbigintAssociated restaurant package.
lock_versionvarcharOptimistic-locking value.
deleted_atdatetimeSoft-delete timestamp.

Migration: 20260420051502_create_hh_package_package_submissions.rb

hh_package_package_draft_versions

ColumnTypeDescription
package_idbigintPolymorphic package ID.
package_typevarcharPolymorphic package type.
previous_stateJSONPackage state before partner edit.
proposed_stateJSONPackage state submitted for review.
changed_fieldsJSONDetected changed fields.
statusvarchar(20)pending, approved, rejected, or invalidated.
applied_atdatetimeTime draft was applied.
deleted_atdatetimeSoft-delete timestamp.

Migration: 20260420051514_create_hh_package_package_draft_versions.rb

Package Creation v2 payment snapshot

The v2 PRD requires a package-level payment snapshot:

  • accepts_vouchers=true displays Option to Pay Now.
  • accepts_vouchers=false displays Pay On-Site Only.
  • Snapshot is created once at package creation.
  • Partner edits do not re-snapshot.
  • Restaurant payment-setting changes do not retroactively mutate snapshots.
  • Admin override must be supported.
  • Missing restaurant configuration falls back to Pay On-Site Only and logs an internal alert.
  • Final snapshot field name is not specified in the PRD.

Improvement:

Feature NameDateWhat ChangedDescription
Package self-service creation2026-05-15Added AYCE and Party Pack partner submission flowPartner package creation now persists a package submission and returns submission_id.
Package edit review2026-05-15Added draft versions and change detectionSignificant package edits are stored as proposed state and reviewed by admins.
Admin package approval2026-05-15Added pending and history review screensAdmins can approve, reject, or open embedded package review.
Submission notifications2026-05-15Added admin and partner workers/mailersNew submissions notify admins; approvals, rejections, and admin edits notify partners.
Frontend package status2026-05-15Added serializer status fields and filtersFrontend can display submission state, rejection reason, submission ID, and edit capability.
Package Creation v2 navigation2026-05-22Moved Add-ons into All PackagesAdd-ons appear in package listing and cannot be edited yet.
Package Creation v2 form2026-05-22Reordered sections and simplified schedule controlsBasic info, pricing, menu, schedule, and marketing cover image follow the new order.
Package Creation v2 payment behavior2026-05-22Replaced editable Payment Info with snapshot behaviorPayment behavior is captured at package creation and remains stable for existing packages.
PRD/backend commission value difference2026-05-15Documented implementation discrepancyAYCE PRD specifies commission default 12.00; PackageDefaultsEnforcer in PR #8001 applies 12.50.
PRD/backend AI triage boundary2026-05-15Documented workflow boundaryPRD specifies AI triage outcomes; PR #8001 provides submission/review infrastructure but does not show AI prompt execution.