-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Mews - Additional components #18120
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Mews - Additional components #18120
Conversation
WalkthroughAdds multiple new Mews actions and polling sources, extends the mews.app API surface and propDefinitions, replaces generic additionalFields with structured filter props across several fetch actions, introduces utils.parseArray, and bumps package and several module versions. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Action as Create Order Action
participant App as Mews App
participant API as Mews API
User->>Action: Provide props (accountId, serviceId, productOrders, items, ...)
Action->>App: ordersCreate({ $, data })
App->>API: POST /orders/add
API-->>App: Response (Order data)
App-->>Action: Response
Action-->>User: Summary "Successfully created order"
sequenceDiagram
autonumber
actor User
participant Action as Update Reservation Action
participant App as Mews App
participant API as Mews API
User->>Action: Provide props (reservationId, fields to update)
Action->>App: reservationsUpdate({ $, data: { ReservationUpdates: [...] }, Reason/Reprice/... })
App->>API: POST /reservations/update
API-->>App: Response
App-->>Action: Response
Action-->>User: Summary "Successfully updated reservation {id}"
sequenceDiagram
autonumber
participant Poller as Platform Poller
participant Source as Bill Closed Source
participant App as Mews App
participant API as Mews API
loop every poll interval
Poller->>Source: invoke poll
Source->>App: billsGetAll({ $, data: { State: "Closed", ClosedUtc: { StartUtc, EndUtc } } })
App->>API: POST /bills/getAll
API-->>App: { Bills: [...] }
App-->>Source: Bills
Source-->>Poller: emit new Bill events (by ClosedUtc)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Assessment against linked issues
Possibly related PRs
Suggested reviewers
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
ad72bd9 to
74feaff
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 9
🧹 Nitpick comments (25)
components/mews/actions/cancel-reservation/cancel-reservation.mjs (1)
18-33: Nit: Improve the action summary for traceability and guard against empty inputIncluding the reservationId in the summary helps with observability in runs. Adding a lightweight guard provides clearer error messages if the prop is missing at runtime (even if propDefinition generally enforces presence).
async run({ $ }) { const { app, reservationId, } = this; + if (!reservationId) { + throw new Error("reservationId is required"); + } const response = await app.reservationsCancel({ $, data: { ReservationIds: [ reservationId, ], }, }); - $.export("summary", "Successfully cancelled reservation"); + $.export("summary", `Successfully cancelled reservation ${reservationId}`); return response; },components/mews/sources/company-created/company-created.mjs (1)
6-6: Align description phrasing with existing sourcesMatch the phrasing used elsewhere (created + polling).
- description: "Emit new event when a company is created", + description: "Emit new companies as they are created (polling)",components/mews/common/utils.mjs (2)
42-63: Guard recursion depth and decrement consistently in parseArrayparseArray doesn’t honor maxDepth unless the input is a stringified array, and recursion for array inputs doesn’t decrement depth. This can lead to excessive recursion on deeply nested arrays and makes maxDepth ineffective in non-string cases.
Apply this diff to add a depth guard and consistently decrement depth on nested calls:
-function parseArray (input, maxDepth = 100) { - if (typeof input === "string") { +function parseArray (input, maxDepth = 100) { + if (maxDepth <= 0) { + return input; + } + if (typeof input === "string") { const trimmed = input.trim(); if (trimmed.startsWith("[") && trimmed.endsWith("]")) { try { const parsed = JSON.parse(trimmed); if (Array.isArray(parsed)) { - return parsed.map((item) => parseArray(item, maxDepth - 1)); + return parsed.map((item) => parseArray(item, maxDepth - 1)); } } catch (e) { throw new Error(`Invalid JSON array format: ${e.message}`); } } - return parseJson(input, maxDepth); + return parseJson(input, maxDepth - 1); } if (Array.isArray(input)) { - return input.map((item) => parseArray(item, maxDepth)); + return input.map((item) => parseArray(item, maxDepth - 1)); } return input; }
42-63: Avoid cross-module ambiguity: parseArray semantics differ from openai/common/helpers.mjsThere’s another parseArray in components/openai/common/helpers.mjs that only maps parseJson over arrays and doesn’t parse stringified arrays. Sharing the same name but different behavior can confuse maintainers.
- Add a short JSDoc describing the stricter semantics here, or
- Consider a more explicit name (e.g., parseArrayDeep or parseArrayStrict) to prevent future misuse.
components/mews/actions/add-customer-file/add-customer-file.mjs (1)
60-61: Harden summary against varying response shapes (FileId vs Id)If the API response doesn’t always expose FileId (or nests it), the summary may print “undefined”. Prefer a resilient fallback.
Apply this diff to guard against shape differences:
- $.export("summary", `Successfully added file with ID \`${response.FileId}\``); - return response; + const fileId = response?.FileId ?? response?.Id ?? response?.File?.Id; + $.export("summary", fileId + ? `Successfully added file with ID \`${fileId}\`` + : "Successfully added file"); + return response;If you have the exact schema of customersAddFile’s response handy, I can tailor this to the definitive field.
components/mews/actions/create-task/create-task.mjs (1)
63-64: Improve summary with task identifier when availableReturning just a generic success message makes it harder to link runs to created tasks.
Apply this diff to include the ID when present:
- $.export("summary", "Successfully created task"); - return response; + const taskId = response?.TaskId ?? response?.Id; + $.export("summary", taskId + ? `Successfully created task (ID: ${taskId})` + : "Successfully created task"); + return response;components/mews/actions/fetch-customers/fetch-customers.mjs (3)
139-176: Auto-include Deleted state when DeletedUtc filters are usedWhen DeletedUtc filters are provided without including "Deleted" in ActivityStates, the API may return nothing. We can include it automatically to reduce footguns.
Apply this diff to compute a safe ActivityStates:
async run({ $ }) { const { app, createdStartUtc, createdEndUtc, updatedStartUtc, updatedEndUtc, deletedStartUtc, deletedEndUtc, activityStates, customerIds, companyIds, emails, firstNames, lastNames, extentCustomers, extentAddresses, } = this; + const needsDeleted = Boolean(deletedStartUtc || deletedEndUtc); + const finalActivityStates = needsDeleted + ? Array.from(new Set([...(activityStates || []), "Deleted"])) + : activityStates; const items = await app.paginate({ requester: app.customersGetAll, requesterArgs: { $, data: { @@ - ActivityStates: activityStates, + ActivityStates: finalActivityStates, CustomerIds: customerIds, CompanyIds: companyIds, - Emails: emails, + Emails: emails?.filter(Boolean), FirstNames: firstNames, LastNames: lastNames, }, }, resultKey: "Customers", });The Emails filter also now ignores empty values that may come from missing emails in options.
119-137: Optional: Enforce at least one filter to avoid massive unbounded fetchesThe Mews Customers GetAll endpoint often expects some filter (or limits) to avoid huge responses. Your description hints “CustomerIds required if no other filter is provided,” but the code doesn’t enforce it.
Add a guard before paginate:
async run({ $ }) { const { @@ extentAddresses, } = this; + if ( + !createdStartUtc && !createdEndUtc && + !updatedStartUtc && !updatedEndUtc && + !deletedStartUtc && !deletedEndUtc && + !activityStates?.length && + !customerIds?.length && + !companyIds?.length && + !emails?.length && + !firstNames?.length && + !lastNames?.length + ) { + throw new Error("Provide at least one filter (e.g., CustomerIds, Dates, Email, Name) to fetch customers."); + }If the API does allow fully unfiltered pagination safely in your environment, feel free to skip this and keep the current behavior.
82-91: Filter out customers without Email in the customcustomerIdpropDefinitionThe override only replaces the
mapperbut still uses the baseoptionsmethod, which returns every customer—including those with noundefinedvalues in your dropdown. To prevent that, override theoptionsmethod to filter out customers missing an email:propDefinition: [ app, "customerId", - () => ({ - mapper: (customer) => ({ - label: `${customer.FirstName} ${customer.LastName}`, - value: customer.Email, - }), - }), + () => ({ + async options() { + const { Customers: customers } = await this.customersGetAll(); + return customers + .filter(customer => customer.Email) // remove entries without email + .map(customer => ({ + label: `${customer.FirstName} ${customer.LastName}`, + value: customer.Email, + })); + }, + }), ],This ensures only customers with a non-falsy
components/mews/actions/fetch-order-items/fetch-order-items.mjs (3)
119-124: Offer currency options via app propDefinition for consistencyLeverage the app’s currency options to drive valid ISO-4217 selections and align with other actions.
- currency: { - type: "string", - label: "Currency", - description: "ISO-4217 code of the Currency the item costs should be converted to.", - optional: true, - }, + currency: { + type: "string", + label: "Currency", + description: "ISO 4217 currency code to convert item costs to.", + optional: true, + propDefinition: [ + app, + "currency", + ], + },
89-98: Broaden Service Order IDs options to include Product Service Orders, not just ReservationsService orders may be Product Service Orders or Reservations. The current propDefinition only exposes Reservations, which can mislead users and hide valid IDs.
serviceOrderIds: { type: "string[]", label: "Service Order IDs", description: "Unique identifiers of the service orders (product service orders or reservations). Required if no other filter is provided. Max 1000 items.", optional: true, - propDefinition: [ - app, - "reservationId", - ], + async options() { + const [{ Reservations }, { ProductServiceOrders }] = await Promise.all([ + this.app.reservationsGetAll(), + this.app.productServiceOrdersGetAll(), + ]); + const reservationOptions = (Reservations || []).map(({ Id: value, Number: label }) => ({ + label: `Reservation ${label}`, + value, + })); + const productServiceOrderOptions = (ProductServiceOrders || []).map(({ Id: value, Number: label }) => ({ + label: `Product Service Order ${label}`, + value, + })); + return [ + ...reservationOptions, + ...productServiceOrderOptions, + ]; + }, },If you prefer to keep the propDefinition approach, we can instead introduce a separate
productServiceOrderIdsprop next toserviceOrderIds. Want me to push that version?
207-216: Optionally omit undefined top-level filters for cleaner requestsAxios/JSON.stringify drops undefined, so this works as-is. Still, explicitly omitting empty filters reduces payload noise and avoids accidental null-ish values if serialization changes.
Example pattern (not exhaustive):
- EnterpriseIds: enterpriseIds, + ...(enterpriseIds?.length && { EnterpriseIds: enterpriseIds }),Apply similarly to other top-level arrays/fields if you like this style.
components/mews/actions/update-customer/update-customer.mjs (3)
156-184: Clarify Classifications: remove “JSON” wording; values are sent as an array of enumsThe prop is a string[] with static options; asking for JSON strings is misleading.
classifications: { type: "string[]", label: "Classifications", - description: "New classifications of the customer in JSON format. Each classification should be a JSON string with the classification ID.", + description: "Classification flags of the customer. Select one or more values.", optional: true, options: [ "None", "PaymasterAccount", "Blacklist", "Media", "LoyaltyProgram", "PreviousComplaint", "Returning", "Staff", "FriendOrFamily", "TopManagement", "Important", "VeryImportant", "Problematic", "Cashlist", "DisabledPerson", "Military", "Airline", "HealthCompliant", "InRoom", "WaitingForRoom", "Student", ], },
203-208: Align Italian Destination Code description with implementation (accepts a string, wrapped as { Value })Implementation wraps a string into
{ Value }, so the description shouldn’t ask for JSON.italianDestinationCode: { type: "string", label: "Italian Destination Code", - description: "New Italian destination code of customer in JSON format. Should include 'Value' property.", + description: "Italian destination code. This value will be wrapped as { Value: <code> } in the request.", optional: true, },
216-284: Optional: Validate that at least one field is being updatedPrevent no-op updates by checking that at least one updatable field is provided besides
customerId.Example insertion right before the API call:
async run({ $ }) { const { app, customerId, title, firstName, lastName, secondLastName, nationalityCode, sex, birthDate, birthPlace, occupation, email, phone, loyaltyCode, notes, carRegistrationNumber, dietaryRequirements, taxIdentificationNumber, companyId, address, classifications, options, italianDestinationCode, italianFiscalCode, } = this; + const hasUpdates = [ + title, firstName, lastName, secondLastName, nationalityCode, sex, birthDate, + birthPlace, occupation, email, phone, loyaltyCode, notes, carRegistrationNumber, + dietaryRequirements, taxIdentificationNumber, companyId, address, + classifications?.length, options?.length, italianDestinationCode, italianFiscalCode, + ].some((v) => v !== undefined && v !== null && (Array.isArray(v) ? v.length > 0 : true)); + + if (!hasUpdates) { + throw new Error("Provide at least one field to update."); + }components/mews/mews.app.mjs (1)
137-142: Travel Agency ID has no options now; confirm intendedIf travel agencies are represented under Companies, consider wiring options like
companyIdfor consistency, or remove if unused.components/mews/actions/get-rate-prices/get-rate-prices.mjs (2)
49-53: Avoid sending undefined optional fields (conditionally include ProductId).Guard the optional ProductId to prevent sending an undefined field to the API.
RateId: rateId, - ProductId: productId, + ...(productId && { ProductId: productId }), FirstTimeUnitStartUtc: firstTimeUnitStartUtc, LastTimeUnitStartUtc: lastTimeUnitStartUtc,
37-46: Validate the time interval before calling the API.Basic checks reduce avoidable API errors due to invalid/unsorted timestamps.
async run({ $ }) { const { app, rateId, productId, firstTimeUnitStartUtc, lastTimeUnitStartUtc, } = this; + // Basic interval validation + const start = new Date(firstTimeUnitStartUtc); + const end = new Date(lastTimeUnitStartUtc); + if (Number.isNaN(start.valueOf()) || Number.isNaN(end.valueOf()) || end < start) { + throw new Error("Invalid time interval: ensure valid ISO 8601 UTC timestamps and that the end is not before the start."); + }components/mews/actions/create-availability-block/create-availability-block.mjs (1)
46-57: Optional: validate mutual exclusivity/prioritization of ReleasedUtc vs RollingReleaseOffset.Docs say ReleasedUtc takes precedence over RollingReleaseOffset. Consider warning or rejecting when both are provided to avoid user confusion.
Example guard (place after destructuring):
- If both provided, either throw or log a warning before request.
components/mews/actions/add-reservation-product/add-reservation-product.mjs (1)
63-72: Avoid mixing propDefinition with an explicittypefor the same prop.Rely on the propDefinition’s type to avoid conflicts or UI confusion.
- unitAmountTaxCodes: { - type: "string[]", + unitAmountTaxCodes: { label: "Unit Amount - Tax Codes", description: "Codes of Tax rates to be applied to the item. (Note, you can only define one tax when sending **Gross Value**. For multiple taxes, use **Net Value**)", optional: true, propDefinition: [ app, "taxRate", ], },components/mews/actions/get-bill-pdf/get-bill-pdf.mjs (2)
52-57: Consider validatingprintReasonlength (max 255) in the actionThe API enforces max length 255 for France LE. Adding a local check prevents avoidable API errors.
Apply a lightweight guard:
printReason, } = this; + if (printReason && printReason.length > 255) { + throw new Error("Print Reason must be 255 characters or fewer."); + }
59-80: Use $.exportFile with arraybuffer responseType to handle binary PDFThe
billsGetPdfcall delegates to the Pipedreamaxioswrapper without an explicitresponseType, so by default it will try to parse JSON and fail on a PDF payload. It also returns the full Axios response instead of the raw bytes needed to write a file.• File: components/mews/actions/get-bill-pdf/get-bill-pdf.mjs
• Lines: 59–80Suggested change:
async run({ $ }) { const { app, billId, billPrintEventId, pdfTemplate, printReason, } = this; - const response = await app.billsGetPdf({ + const { data } = await app.billsGetPdf({ + $, + responseType: "arraybuffer", // ensure binary PDF data: { BillId: billId, BillPrintEventId: billPrintEventId, PdfTemplate: pdfTemplate, PrintReason: printReason, }, }); - $.export("summary", `Successfully retrieved PDF for bill ${billId}`); - return response; + const filename = `bill-${billId}${pdfTemplate ? `-${pdfTemplate}` : ""}.pdf`; + await $.exportFile(filename, data); + $.export("summary", `Successfully retrieved PDF for bill ${billId}`); + return { billId, filename }; },components/mews/actions/fetch-products/fetch-products.mjs (1)
48-53: Honor API default for IncludeDefault, or set it explicitly based on ProductIdsThe description states: if Product IDs are provided, Include Default defaults to true; otherwise false. Today, you always pass
IncludeDefault: includeDefaultwhich isundefinedwhen not set. If the app request builder stripsundefined, the API will apply its default. If not, better to compute the default explicitly.Apply:
} = this; - const items = await app.paginate({ + const effectiveIncludeDefault = + includeDefault ?? ((Array.isArray(productIds) && productIds.length > 0) ? true : false); + + const items = await app.paginate({ requester: app.productsGetAll, requesterArgs: { $, - data: { - ServiceIds: serviceIds, + data: { + ServiceIds: serviceIds, ...(updatedStartUtc || updatedEndUtc) && { UpdatedUtc: { StartUtc: updatedStartUtc, EndUtc: updatedEndUtc, }, }, - EnterpriseIds: enterpriseIds, - ProductIds: productIds, - IncludeDefault: includeDefault, + ...(enterpriseIds?.length) && { EnterpriseIds: enterpriseIds }, + ...(productIds?.length) && { ProductIds: productIds }, + ...(effectiveIncludeDefault !== undefined) && { IncludeDefault: effectiveIncludeDefault }, }, }, resultKey: "Products", });This also avoids sending empty arrays/undefined keys, matching patterns used in other actions in this PR.
components/mews/actions/update-reservation/update-reservation.mjs (2)
12-29: Top-level flags should be included conditionally to avoid sending undefined
Reason,Reprice, andApplyCancellationFeeare always included, even whenundefined. If the client doesn’t stripundefined, this may cause payload issues or unintended defaults. Other actions in the repo conditionally include fields.data: { - Reason: reason, - Reprice: reprice, - ApplyCancellationFee: applyCancellationFee, + ...(reason && { Reason: reason }), + ...(reprice !== undefined && { Reprice: reprice }), + ...(applyCancellationFee !== undefined && { ApplyCancellationFee: applyCancellationFee }), ReservationUpdates: [
37-60: Clarify how to clear fields that require explicit null (Value: null)For fields like
channelNumber,startUtc,endUtc,releasedUtc, etc., the docs mention “Pass an object with Value or null if the field should not be updated.” The current implementation only supports setting a new value; there’s no way for users to send anullto clear. Consider a pattern (used in other integrations) that adds a boolean “clearX” prop or accepts JSON input for theValue.If you want, I can draft a minimal “clear” pattern for the string fields to support
Value: nullupdates.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (28)
components/mews/actions/add-customer-file/add-customer-file.mjs(1 hunks)components/mews/actions/add-reservation-companion/add-reservation-companion.mjs(1 hunks)components/mews/actions/add-reservation-product/add-reservation-product.mjs(1 hunks)components/mews/actions/cancel-reservation/cancel-reservation.mjs(1 hunks)components/mews/actions/create-availability-block/create-availability-block.mjs(1 hunks)components/mews/actions/create-order/create-order.mjs(1 hunks)components/mews/actions/create-reservation/create-reservation.mjs(1 hunks)components/mews/actions/create-task/create-task.mjs(1 hunks)components/mews/actions/fetch-customers/fetch-customers.mjs(1 hunks)components/mews/actions/fetch-order-items/fetch-order-items.mjs(1 hunks)components/mews/actions/fetch-products/fetch-products.mjs(1 hunks)components/mews/actions/fetch-reservations/fetch-reservations.mjs(1 hunks)components/mews/actions/get-bill-pdf/get-bill-pdf.mjs(1 hunks)components/mews/actions/get-rate-prices/get-rate-prices.mjs(1 hunks)components/mews/actions/update-customer/update-customer.mjs(1 hunks)components/mews/actions/update-reservation/update-reservation.mjs(1 hunks)components/mews/common/utils.mjs(1 hunks)components/mews/mews.app.mjs(9 hunks)components/mews/package.json(1 hunks)components/mews/sources/bill-closed/bill-closed.mjs(1 hunks)components/mews/sources/company-created/company-created.mjs(1 hunks)components/mews/sources/customer-created/customer-created.mjs(1 hunks)components/mews/sources/order-item-created/order-item-created.mjs(1 hunks)components/mews/sources/order-item-updated/order-item-updated.mjs(1 hunks)components/mews/sources/product-service-order-created/product-service-order-created.mjs(1 hunks)components/mews/sources/reservation-cancelled/reservation-cancelled.mjs(1 hunks)components/mews/sources/reservation-created/reservation-created.mjs(1 hunks)components/mews/sources/reservation-updated/reservation-updated.mjs(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (12)
components/mews/common/utils.mjs (1)
components/openai/common/helpers.mjs (1)
parseArray(82-88)
components/mews/actions/create-order/create-order.mjs (3)
components/mews/actions/add-reservation-product/add-reservation-product.mjs (1)
response(88-103)components/mews/actions/create-reservation/create-reservation.mjs (1)
response(118-157)components/mews/actions/update-customer/update-customer.mjs (1)
response(244-279)
components/mews/actions/fetch-products/fetch-products.mjs (5)
components/mews/actions/fetch-customers/fetch-customers.mjs (1)
items(139-175)components/mews/actions/fetch-order-items/fetch-order-items.mjs (1)
items(172-219)components/mews/actions/fetch-reservations/fetch-reservations.mjs (1)
items(228-290)components/mews/sources/common/polling.mjs (1)
items(97-109)components/wix_api_key/actions/add-products-to-collection/add-products-to-collection.mjs (1)
productIds(37-39)
components/mews/actions/fetch-customers/fetch-customers.mjs (4)
components/mews/actions/fetch-products/fetch-products.mjs (1)
items(66-84)components/mews/actions/fetch-order-items/fetch-order-items.mjs (1)
items(172-219)components/mews/actions/fetch-reservations/fetch-reservations.mjs (1)
items(228-290)components/mews/sources/common/polling.mjs (1)
items(97-109)
components/mews/actions/add-reservation-product/add-reservation-product.mjs (3)
components/mews/actions/add-reservation-companion/add-reservation-companion.mjs (1)
response(33-39)components/mews/actions/create-order/create-order.mjs (1)
response(138-150)components/mews/actions/create-reservation/create-reservation.mjs (1)
response(118-157)
components/mews/actions/create-availability-block/create-availability-block.mjs (2)
components/mews/actions/create-reservation/create-reservation.mjs (1)
response(118-157)components/mews/actions/get-rate-prices/get-rate-prices.mjs (1)
response(46-54)
components/mews/actions/update-customer/update-customer.mjs (3)
components/mews/actions/add-customer-file/add-customer-file.mjs (1)
response(50-58)components/mews/actions/create-order/create-order.mjs (1)
response(138-150)components/mews/actions/update-reservation/update-reservation.mjs (1)
response(227-331)
components/mews/actions/fetch-order-items/fetch-order-items.mjs (4)
components/mews/actions/fetch-products/fetch-products.mjs (1)
items(66-84)components/mews/actions/fetch-customers/fetch-customers.mjs (1)
items(139-175)components/mews/actions/fetch-reservations/fetch-reservations.mjs (1)
items(228-290)components/mews/sources/common/polling.mjs (1)
items(97-109)
components/mews/actions/get-rate-prices/get-rate-prices.mjs (2)
components/mews/actions/create-availability-block/create-availability-block.mjs (1)
response(167-198)components/mews/mews.app.mjs (1)
response(551-560)
components/mews/actions/fetch-reservations/fetch-reservations.mjs (4)
components/mews/actions/fetch-products/fetch-products.mjs (1)
items(66-84)components/mews/actions/fetch-customers/fetch-customers.mjs (1)
items(139-175)components/mews/actions/fetch-order-items/fetch-order-items.mjs (1)
items(172-219)components/mews/sources/common/polling.mjs (1)
items(97-109)
components/mews/actions/add-reservation-companion/add-reservation-companion.mjs (2)
components/mews/actions/cancel-reservation/cancel-reservation.mjs (1)
response(23-30)components/mews/actions/add-reservation-product/add-reservation-product.mjs (1)
response(88-103)
components/mews/actions/update-reservation/update-reservation.mjs (3)
components/mews/actions/create-availability-block/create-availability-block.mjs (1)
response(167-198)components/mews/actions/create-reservation/create-reservation.mjs (1)
response(118-157)components/mews/actions/update-customer/update-customer.mjs (1)
response(244-279)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
- GitHub Check: Lint Code Base
- GitHub Check: Publish TypeScript components
- GitHub Check: Verify TypeScript components
- GitHub Check: pnpm publish
🔇 Additional comments (31)
components/mews/package.json (1)
3-3: Version bump looks goodPatch version bump aligns with the set of additive changes across actions/sources. No issues spotted.
components/mews/sources/reservation-updated/reservation-updated.mjs (1)
8-8: Patch version bump only — LGTMNo functional changes introduced. The polling configuration (UpdatedUtc for both sort and filter fields) remains consistent with the base source expectations.
components/mews/sources/product-service-order-created/product-service-order-created.mjs (1)
8-8: Patch version bump only — LGTMNo behavioral changes. Polling continues to target CreatedUtc, which matches the event semantics for “created” sources.
components/mews/actions/cancel-reservation/cancel-reservation.mjs (1)
7-7: Patch version bump only — LGTMNo logic changes. Action remains backward-compatible.
components/mews/sources/order-item-updated/order-item-updated.mjs (1)
8-8: Patch version bump only — LGTMNo runtime or API changes. Polling fields remain consistent with “updated” semantics.
components/mews/sources/reservation-created/reservation-created.mjs (1)
8-8: LGTM: Patch version bump onlyVersion bump to 0.0.2 with no behavioral changes looks good and aligns with the broader release.
components/mews/sources/order-item-created/order-item-created.mjs (1)
8-8: LGTM: Patch version bump onlyVersion bump to 0.0.2 with no behavioral changes looks good and is consistent with other sources in this PR.
components/mews/actions/create-reservation/create-reservation.mjs (1)
8-8: LGTM: Patch version bump onlyNo logic changes alongside the version bump; looks good.
components/mews/sources/reservation-cancelled/reservation-cancelled.mjs (2)
8-8: LGTM: Patch version bump onlyNo functional changes; version bump is consistent with the rest of the sources.
24-29: All usages of “CanceledUtc” and “Canceled” are correct
Verified across the codebase and Mews Connector API docs that the cancellation timestamp property is “CanceledUtc” (single L) and the reservation state string is “Canceled” (single L). No changes required.components/mews/sources/company-created/company-created.mjs (2)
1-31: Solid new polling source; accessor methods match Mews conventionsThe requester, result key, ID resolver, and date fields are consistent with other Mews sources. Good use of the common polling base.
12-14: mews.app.mjs exposes required methods
The app module defines companiesGetAll, orderItemsGetAll, and reservationsGetAll (see lines 355–359, 391–394, 457–460), so the source’s call to this.app.companiesGetAll is valid. No changes needed.components/mews/common/utils.mjs (1)
51-55: Confirm strict failure on invalid JSON array is desired UXUnlike parseJson (which silently returns the original string on parse failure), parseArray throws on invalid JSON arrays. This will surface as a hard error in actions that use it. If that’s intentional (to fail fast when an array is required), great—just confirm this difference is expected across all new usages in this PR.
Would you like this to be strict (throw) or permissive (fallback to original string)? If permissive, I can provide a patch to mirror parseJson’s behavior.
components/mews/sources/customer-created/customer-created.mjs (1)
3-31: LGTM: Polling source correctly targets CreatedUtc and maps IDsThe source aligns with the common polling base, uses CreatedUtc for both emitted timestamp and filter, and maps Id safely. Looks good.
components/mews/actions/fetch-reservations/fetch-reservations.mjs (1)
228-290: LGTM on explicit payload construction and paginationClear conditional blocks for every UTC filter, top-level array filters, and pluralized summary. This mirrors the updated pattern across other fetch actions.
components/mews/mews.app.mjs (3)
7-27: General: option mappings LGTMReservations/Services/Resources/Rates/Companies/Departments/Countries/Credit Cards/Availability Blocks selectors correctly map label/value to API shapes. Nice improvement over raw payload fields.
Also applies to: 83-91, 111-119, 127-135, 149-157, 159-173, 174-207, 209-225, 262-276, 278-291, 311-326
535-573: Paginate helper is solidCursor-based pagination with maxRequests guard and consistent Limitation payload construction looks good.
451-456: Confirm ratesGetPricing endpoint path usage
- Repo-local search found only the single reference at components/mews/mews.app.mjs:453
- No typos or duplicate paths detected in the codebase
Please double-check that “/rates/getPricing” exactly matches the latest Mews API documentation.
components/mews/sources/bill-closed/bill-closed.mjs (1)
3-36: LGTM: polling source correctly filters Closed bills and uses ClosedUtc for windowingRequester/resultKey/date field wiring matches the shared polling base. Static
State: "Closed"filter is appropriate.components/mews/actions/get-rate-prices/get-rate-prices.mjs (1)
46-55: Confirm inclusion of ServiceId in ratesGetPricing requestThe
ratesGetPricingwrapper simply spreads yourargsinto the request – it doesn’t enforce any particular payload shape:• In components/mews/mews.app.mjs (lines 451–454), the implementation is:
ratesGetPricing(args = {}) { return this._makeRequest({ path: "/rates/getPricing", ...args, }); },• No other call sites supply a
ServiceId, and there’s no default or validation in the wrapper.Please verify against the official Mews API documentation whether the
/rates/getPricingendpoint requires aServiceIdalongside yourRateId(even if it’s optional). If it is required, update your action to include:data: { RateId: rateId, ProductId: productId, + ServiceId: serviceId, // <— add this if required by the API FirstTimeUnitStartUtc: firstTimeUnitStartUtc, LastTimeUnitStartUtc: lastTimeUnitStartUtc, },components/mews/actions/add-reservation-companion/add-reservation-companion.mjs (2)
33-41: Straightforward, consistent API call. LGTM.The request shape matches the endpoint expectations and summary is useful.
33-41: reservationsAddCompanion signature verified
- In components/mews/mews.app.mjs (lines 379–382),
reservationsAddCompanion(args = {})merges...argsinto the request.- The call in add-reservation-companion.mjs supplies
$anddata: { ReservationId, CustomerId }, matching the wrapper’s signature.No changes required.
components/mews/actions/get-bill-pdf/get-bill-pdf.mjs (1)
24-51: Good use of enumerated PDF template optionsClear labels and constrained values reduce input errors and align with the API’s expected enum.
components/mews/actions/fetch-products/fetch-products.mjs (3)
7-7: Version bump looks appropriate for the breaking prop changesSwitching from
additionalFieldsto structured props and changing the public surface warrants0.0.2. Good.
11-19: Confirm multi-select compatibility forserviceIdspropDefinitionUsing
propDefinition: [app, "serviceId"]withtype: "string[]"is a common pattern for multi-selects. Ensure the underlying propDefinition supplies options that work with array types.If needed, align with patterns used in other actions that expose multi-select IDs to ensure consistent UX.
86-89: Nice touch on pluralized summaryReadable step output helps. LGTM.
components/mews/actions/update-reservation/update-reservation.mjs (5)
6-9: Public contract change is justified and documentedVersion bump to 0.0.2 with enhanced props and link to docs is appropriate.
61-84:personCountstyped as string[] is fine if utils.parseArray handles JSON strings per itemGiven the examples, users will likely paste JSON per element. Confirm
utils.parseArraymaps a string[] like ['{"AgeCategoryId":"...","Count":2}', ...] to an object[] as required by the API.If not, switch the prop to a single JSON string and parse via
utils.parseJsonfor fewer UX footguns.
137-172:timeUnitPricesparsing mirrorspersonCounts— confirm utils.parseArray handles nested Amount objectsSame concern: ensure
utils.parseArraycorrectly parses complex nested objects per array item and surfaces a good error message if parsing fails.Optional: add a quick try/catch around parsing to throw a nicer validation error before the API call.
311-327: Correct handling of booleans with explicit undefined checksUsing
!== undefinedensures false values aren’t dropped. Nice.
333-334: Good summary including the reservation IDHelpful for run history.
components/mews/actions/add-reservation-product/add-reservation-product.mjs
Show resolved
Hide resolved
components/mews/actions/create-availability-block/create-availability-block.mjs
Show resolved
Hide resolved
components/mews/actions/create-availability-block/create-availability-block.mjs
Show resolved
Hide resolved
cb5fa86 to
37d3820
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ Duplicate comments (5)
components/mews/actions/create-order/create-order.mjs (2)
12-17: Remove unusedaccountTypepropDefinitionThis prop isn’t used in
run()and isn’t supported by the Mews Add order API. Leaving it confuses users.app, - accountType: { - propDefinition: [ - app, - "accountType", - ], - },
138-149: Parse arrays once, validate at least one of ProductOrders/Items is provided, and omit undefinedsAvoid double parsing, proactively prevent empty payload errors, and don’t send undefined fields.
- const response = await app.ordersCreate({ - $, - data: { - AccountId: accountId, - ServiceId: serviceId, - BillId: billId, - LinkedReservationId: linkedReservationId, - ConsumptionUtc: consumptionUtc, - Notes: notes, - ProductOrders: utils.parseArray(productOrders), - Items: utils.parseArray(items), - }, - }); + const parsedProductOrders = utils.parseArray(productOrders); + const parsedItems = utils.parseArray(items); + if ((!parsedProductOrders || parsedProductOrders.length === 0) + && (!parsedItems || parsedItems.length === 0)) { + throw new Error("Provide at least one Product Order or Item."); + } + + const response = await app.ordersCreate({ + $, + data: { + AccountId: accountId, + ServiceId: serviceId, + ...(billId && { BillId: billId }), + ...(linkedReservationId && { LinkedReservationId: linkedReservationId }), + ...(consumptionUtc && { ConsumptionUtc: consumptionUtc }), + ...(notes && { Notes: notes }), + ...(parsedProductOrders?.length && { ProductOrders: parsedProductOrders }), + ...(parsedItems?.length && { Items: parsedItems }), + }, + });components/mews/mews.app.mjs (2)
235-261: LGTM: options handlers correctly usethis.*app methods.The previous
this.app.*bug is resolved. Usingthis.companiesGetAll()/this.customersGetAll()is correct within propDefinitions.
294-310: Align creditCardId description with actual type and behavior.Type is string and options return Id strings, but the description still asks for an object with Value. Actions wrap the Id at call-time.
creditCardId: { type: "string", label: "Credit Card ID", - description: "Identifier of CreditCard belonging to Customer who owns the reservation. Pass an object with 'Value' property or null if the credit card should not be updated.", + description: "Identifier of a Credit Card belonging to the reservation owner. Provide the Id; actions will wrap it as { Value: <Id> } when sending to the API.", optional: true,components/mews/actions/add-reservation-product/add-reservation-product.mjs (1)
75-86: Validate unit amount: require exactly one of GrossValue or NetValue.Prevent avoidable API errors by enforcing this constraint up front.
async run({ $ }) { const { app, reservationId, productId, startUtc, endUtc, count, unitAmountGrossValue, unitAmountNetValue, unitAmountCurrency, unitAmountTaxCodes, } = this; + if (count !== undefined && count <= 0) { + throw new Error("Count must be a positive integer."); + } + + const hasGross = unitAmountGrossValue !== undefined && unitAmountGrossValue !== null && unitAmountGrossValue !== ""; + const hasNet = unitAmountNetValue !== undefined && unitAmountNetValue !== null && unitAmountNetValue !== ""; + if (hasGross && hasNet) { + throw new Error("Provide either Unit Amount - Gross Value or Unit Amount - Net Value, not both."); + } + if (!hasGross && !hasNet && (unitAmountCurrency || (unitAmountTaxCodes && unitAmountTaxCodes.length))) { + throw new Error("Provide either Unit Amount - Gross Value or Unit Amount - Net Value when specifying currency or tax codes."); + }
🧹 Nitpick comments (16)
components/mews/actions/create-order/create-order.mjs (1)
141-149: Optional: avoid sending undefined for optional fieldsIf the HTTP layer doesn’t strip undefined, API may reject payload. The diff above already applies conditional spreads.
components/mews/actions/fetch-customers/fetch-customers.mjs (3)
77-92: Tighten email picker mapping for clarity and resilienceCurrent labels omit the email; values may be undefined for customers without email. Improve discoverability and reduce ambiguity.
propDefinition: [ app, "customerId", () => ({ - mapper: (customer) => ({ - label: `${customer.FirstName} ${customer.LastName}`, - value: customer.Email, - }), + mapper: (customer) => ({ + // Include email in the label for clarity and disambiguation + label: `${customer.FirstName ?? ""} ${customer.LastName ?? ""} — ${customer.Email ?? ""}`.trim(), + value: customer.Email, + }), }), ],
121-137: Auto-include 'Deleted' in ActivityStates when DeletedUtc filters are used; enforce single CompanyIdAlign behavior with your own prop docs (“ActivityStates value 'Deleted' should be provided…”, “Max 1 item”), reducing surprising results and API errors.
async run({ $ }) { const { app, createdStartUtc, createdEndUtc, updatedStartUtc, updatedEndUtc, deletedStartUtc, deletedEndUtc, activityStates, customerIds, companyIds, emails, firstNames, lastNames, extentCustomers, extentAddresses, } = this; + // If DeletedUtc is used but 'Deleted' isn't in ActivityStates, auto-include it. + const deletedAwareActivityStates = (deletedStartUtc || deletedEndUtc) + ? (activityStates?.includes("Deleted") + ? activityStates + : [ ...(activityStates || []), "Deleted" ]) + : activityStates; + + // Enforce API note: CompanyIds max 1 item + if (companyIds?.length > 1) { + throw new Error("Provide at most 1 Company ID as per Mews API."); + }
162-172: Wire the derived ActivityStates into the payloadUse the computed
deletedAwareActivityStateswhen building the request.Extent: { Customers: extentCustomers, Addresses: extentAddresses, }, - ActivityStates: activityStates, + ActivityStates: deletedAwareActivityStates, CustomerIds: customerIds, CompanyIds: companyIds, Emails: emails, FirstNames: firstNames, LastNames: lastNames,components/mews/actions/create-task/create-task.mjs (1)
52-61: Only send Description when providedKeep payloads minimal; avoid sending undefined.
const response = await app.tasksCreate({ $, data: { Name: name, - Description: description, + ...(description && { Description: description }), DepartmentId: departmentId, ServiceOrderId: serviceOrderId, DeadlineUtc: deadlineUtc, }, });components/mews/actions/get-bill-pdf/get-bill-pdf.mjs (1)
24-51: Optional: provide a default PDF templateSetting a sensible default improves UX; “Detailed” is typically expected.
pdfTemplate: { type: "string", label: "PDF Template", description: "Bill PDF template type. If not specified, the default template is used.", - optional: true, + optional: true, + default: "Detailed", options: [components/mews/actions/fetch-order-items/fetch-order-items.mjs (2)
148-170: Guard against unbounded queries by requiring at least one filterThe API typically expects some filter; failing to set one can be slow/heavy. Fail-fast with a clear message.
async run({ $ }) { const { app, createdStartUtc, createdEndUtc, updatedStartUtc, updatedEndUtc, consumedStartUtc, consumedEndUtc, canceledStartUtc, canceledEndUtc, closedStartUtc, closedEndUtc, enterpriseIds, orderItemIds, accountIds, serviceOrderIds, serviceIds, billIds, currency, accountingStates, types, } = this; + const hasAnyFilter = Boolean( + createdStartUtc || createdEndUtc || + updatedStartUtc || updatedEndUtc || + consumedStartUtc || consumedEndUtc || + canceledStartUtc || canceledEndUtc || + closedStartUtc || closedEndUtc || + enterpriseIds?.length || orderItemIds?.length || accountIds?.length || + serviceOrderIds?.length || serviceIds?.length || billIds?.length || + currency || accountingStates?.length || types?.length + ); + if (!hasAnyFilter) { + throw new Error("Provide at least one filter (e.g., time range, IDs, or states) to fetch order items."); + }
177-206: Reduce duplication when building date interval objectsThis pattern is repeated across actions. Consider a small helper (e.g., buildInterval(start, end, fieldName)) in common utils to improve maintainability.
I can extract a shared helper and update all fetch actions in this PR for consistency. Want me to follow up with a patch?
components/mews/actions/update-reservation/update-reservation.mjs (4)
37-42: Fix doc/type mismatch for Value-wrapped fields (users should enter raw values).These props are typed as string/boolean, and the run() method correctly wraps them as
{ Value }. However, the descriptions instruct users to "Pass an object with 'Value' property or null", which is misleading for the component API.Recommend updating the descriptions to reflect that users should supply raw values and leave blank to keep unchanged. If “clear/unset” is needed, that’s currently not supported (see clearing comment below).
Apply this pattern (example diffs shown for a few props; repeat similarly for the rest):
- description: "Number of the reservation within the Channel (i.e. OTA, GDS, CRS, etc) in case the reservation group originates there (e.g. Booking.com confirmation number). Pass an object with 'Value' property or null if the channel number should not be updated.", + description: "Number of the reservation within the Channel (e.g. Booking.com confirmation number). Provide the value to set; leave blank to keep unchanged.",- description: "Reservation start in UTC timezone in ISO 8601 format. Pass an object with 'Value' property or null if the start time should not be updated.", + description: "Reservation start in UTC timezone in ISO 8601 format. Provide the value to set; leave blank to keep unchanged.",- description: "Reservation end in UTC timezone in ISO 8601 format. Pass an object with 'Value' property or null if the end time should not be updated.", + description: "Reservation end in UTC timezone in ISO 8601 format. Provide the value to set; leave blank to keep unchanged.",- description: "Date when the optional reservation is released in UTC timezone in ISO 8601 format. Pass an object with 'Value' property or null if the release time should not be updated.", + description: "Date when the optional reservation is released in UTC timezone in ISO 8601 format. Provide the value to set; leave blank to keep unchanged.",- description: "Identifier of the assigned Resource. If the assigned resource is locked, see AssignedResourceLocked for updating the assigned resource. Pass an object with 'Value' property or null if the assigned resource should not be updated.", + description: "Identifier of the assigned Resource. If the assigned resource is locked, see AssignedResourceLocked. Provide the value to set; leave blank to keep unchanged.",- description: "Identifier of the requested ResourceCategory. Pass an object with 'Value' property or null if resource category should not be updated.", + description: "Identifier of the requested ResourceCategory. Provide the value to set; leave blank to keep unchanged.",- description: "Purpose of the reservation. Pass an object with 'Value' property (Business, Leisure, Student) or null if the purpose should not be updated.", + description: "Purpose of the reservation. One of: Business, Leisure, Student. Provide the value to set; leave blank to keep unchanged.",- description: "Identifier of the Customer on whose behalf the reservation was made. Pass an object with 'Value' property or null if the booker should not be updated.", + description: "Identifier of the Customer on whose behalf the reservation was made. Provide the value to set; leave blank to keep unchanged.",- description: "Whether the reservation should be locked to the assigned Resource. To reassign the reservation to a new Resource, first set AssignedResourceLocked to false to unlock the resource. Then, assign the reservation to a new Resource by setting AssignedResourceId to the new resource ID. Pass an object with 'Value' property (boolean) or null if the lock should not be updated.", + description: "Whether the reservation should be locked to the assigned Resource. To reassign, first set AssignedResourceLocked to false, then set AssignedResourceId to the new resource ID. Provide the boolean value to set; leave blank to keep unchanged.",Also applies to: 43-48, 49-54, 55-60, 85-90, 91-96, 119-124, 173-180, 181-186
61-84: Clarify input format for string[] props that expect object arrays.Both personCounts and timeUnitPrices are typed as string[], but the descriptions/examples show arrays of objects. If the intention is “one JSON object per item”, please clarify that each item in the array should be a JSON string representing the object (parsed via utils.parseArray at runtime).
For example:
- description: `Number of people per age category the reservation is for. If supplied, the person counts will be replaced. Each item should contain: + description: `Number of people per age category the reservation is for. If supplied, the person counts will be replaced. + +Provide each item as a JSON string representing an object with: - \`AgeCategoryId\` (string, required): Unique identifier of the Age category - \`Count\` (integer, required): Number of people of a given age category. Only positive value is acceptedAnd similarly for Time Unit Prices (note at the top that each array item is a JSON string representing the object shown in the example).
Also applies to: 137-171
200-225: Cannot clear/unset fields that use { Value } wrappers (no way to send Value: null).Because fields are included only when truthy (e.g.
(channelNumber && {...})), users can update a value but can’t explicitly clear it (send{ Value: null }). If the API supports clearing, expose a way to do it.Two lightweight patterns:
- Add paired boolean “clear” toggles (e.g. clearChannelNumber). If true, send
{ Value: null }and ignore the input value.- Add a generic string[] prop, e.g. clearFields, and map it to those wrappers dynamically.
Example pattern for ChannelNumber (apply similarly to other wrappers):
props: { app, + clearChannelNumber: { + type: "boolean", + label: "Clear Channel Number", + description: "If true, clears the Channel Number (sends { Value: null }).", + optional: true, + }, channelNumber: { type: "string", label: "Channel Number", - description: "Number of the reservation within the Channel (i.e. OTA, GDS, CRS, etc) in case the reservation group originates there (e.g. Booking.com confirmation number). Pass an object with 'Value' property or null if the channel number should not be updated.", + description: "Number of the reservation within the Channel (e.g., Booking.com confirmation number).", optional: true, },- ...(channelNumber && { - ChannelNumber: { - Value: channelNumber, - }, - }), + ...((this.clearChannelNumber || channelNumber) && { + ChannelNumber: { + Value: this.clearChannelNumber ? null : channelNumber, + }, + }),If you prefer the generic list approach, I can draft that refactor.
Also applies to: 236-327
12-23: Reason should be required when changing price-related fields (guard before API call).Per description, Reason is required when updating the price. That typically includes reprice=true, changing RateId, or providing TimeUnitPrices. Add a minimal validation before calling the API.
async run({ $ }) { const { app, reason, reprice, applyCancellationFee, reservationId, channelNumber, startUtc, endUtc, releasedUtc, personCounts, assignedResourceId, requestedCategoryId, travelAgencyId, companyId, businessSegmentId, purpose, - rateId, + rateId, creditCardId, timeUnitPrices, bookerId, assignedResourceLocked, availabilityBlockId, optionsOwnerCheckedIn, } = this; + // Minimal validation for price updates + const isPriceUpdate = + reprice === true + || !!rateId + || (Array.isArray(timeUnitPrices) && timeUnitPrices.length > 0); + if (isPriceUpdate && !reason) { + throw new Error("Reason is required when updating reservation pricing (reprice, rateId, or timeUnitPrices)."); + }Please confirm against Mews’ latest docs whether changing RateId should also require a Reason.
Also applies to: 219-225
components/mews/mews.app.mjs (1)
137-142: Optional: add options loader for Travel Agency.Currently
travelAgencyIdis free-form with no options. If Travel Agencies are represented among Companies in your API scope, consider providing options viacompaniesGetAll()for parity withcompanyId.Example:
travelAgencyId: { type: "string", label: "Travel Agency ID", description: "Identifier of the Travel Agency.", optional: true, + async options() { + const { Companies: companies } = await this.companiesGetAll(); + return companies.map(({ Name: label, Id: value }) => ({ label, value })); + }, },If a narrower endpoint/filter exists for Travel Agencies, that’d be preferred—let me know and I can adjust the mapping.
components/mews/actions/add-reservation-product/add-reservation-product.mjs (1)
88-103: Only include UnitAmount if any of its fields are provided.If none of the UnitAmount fields are set, omit the object entirely to avoid sending empty payloads.
- const response = await app.reservationsAddProduct({ + const anyUnitAmount = + unitAmountGrossValue !== undefined && unitAmountGrossValue !== null && unitAmountGrossValue !== "" + || unitAmountNetValue !== undefined && unitAmountNetValue !== null && unitAmountNetValue !== "" + || !!unitAmountCurrency + || (Array.isArray(unitAmountTaxCodes) && unitAmountTaxCodes.length > 0); + const response = await app.reservationsAddProduct({ $, data: { ReservationId: reservationId, ProductId: productId, StartUtc: startUtc, EndUtc: endUtc, Count: count, - UnitAmount: { - Currency: unitAmountCurrency, - GrossValue: unitAmountGrossValue, - NetValue: unitAmountNetValue, - TaxCodes: unitAmountTaxCodes, - }, + ...(anyUnitAmount && { + UnitAmount: { + Currency: unitAmountCurrency, + GrossValue: unitAmountGrossValue, + NetValue: unitAmountNetValue, + TaxCodes: unitAmountTaxCodes, + }, + }), }, });components/mews/actions/fetch-products/fetch-products.mjs (2)
56-64: Honor described default for Include Default.The description states: if Product IDs are provided, Include Default defaults to true; otherwise false. Implement that computed default.
async run({ $ }) { const { app, serviceIds, updatedStartUtc, updatedEndUtc, enterpriseIds, productIds, - includeDefault, + includeDefault, } = this; + const includeDefaultComputed = + this.includeDefault ?? Boolean(Array.isArray(productIds) && productIds.length); + const items = await app.paginate({ requester: app.productsGetAll, requesterArgs: { $, data: { ServiceIds: serviceIds, ...(updatedStartUtc || updatedEndUtc) && { UpdatedUtc: { StartUtc: updatedStartUtc, EndUtc: updatedEndUtc, }, }, EnterpriseIds: enterpriseIds, ProductIds: productIds, - IncludeDefault: includeDefault, + IncludeDefault: includeDefaultComputed, }, }, resultKey: "Products", });Also applies to: 66-84
20-31: Optional: Validate the UpdatedUtc interval (max 3 months).You note a 3-month max interval; consider a lightweight check to fail fast with a helpful error if the range exceeds this, rather than letting the API reject it.
I can add a small date-diff validation if desired.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (28)
components/mews/actions/add-customer-file/add-customer-file.mjs(1 hunks)components/mews/actions/add-reservation-companion/add-reservation-companion.mjs(1 hunks)components/mews/actions/add-reservation-product/add-reservation-product.mjs(1 hunks)components/mews/actions/cancel-reservation/cancel-reservation.mjs(1 hunks)components/mews/actions/create-availability-block/create-availability-block.mjs(1 hunks)components/mews/actions/create-order/create-order.mjs(1 hunks)components/mews/actions/create-reservation/create-reservation.mjs(1 hunks)components/mews/actions/create-task/create-task.mjs(1 hunks)components/mews/actions/fetch-customers/fetch-customers.mjs(1 hunks)components/mews/actions/fetch-order-items/fetch-order-items.mjs(1 hunks)components/mews/actions/fetch-products/fetch-products.mjs(1 hunks)components/mews/actions/fetch-reservations/fetch-reservations.mjs(1 hunks)components/mews/actions/get-bill-pdf/get-bill-pdf.mjs(1 hunks)components/mews/actions/get-rate-prices/get-rate-prices.mjs(1 hunks)components/mews/actions/update-customer/update-customer.mjs(1 hunks)components/mews/actions/update-reservation/update-reservation.mjs(1 hunks)components/mews/common/utils.mjs(1 hunks)components/mews/mews.app.mjs(9 hunks)components/mews/package.json(1 hunks)components/mews/sources/bill-closed/bill-closed.mjs(1 hunks)components/mews/sources/company-created/company-created.mjs(1 hunks)components/mews/sources/customer-created/customer-created.mjs(1 hunks)components/mews/sources/order-item-created/order-item-created.mjs(1 hunks)components/mews/sources/order-item-updated/order-item-updated.mjs(1 hunks)components/mews/sources/product-service-order-created/product-service-order-created.mjs(1 hunks)components/mews/sources/reservation-cancelled/reservation-cancelled.mjs(1 hunks)components/mews/sources/reservation-created/reservation-created.mjs(1 hunks)components/mews/sources/reservation-updated/reservation-updated.mjs(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- components/mews/sources/order-item-created/order-item-created.mjs
- components/mews/sources/reservation-updated/reservation-updated.mjs
🚧 Files skipped from review as they are similar to previous changes (17)
- components/mews/sources/reservation-created/reservation-created.mjs
- components/mews/sources/product-service-order-created/product-service-order-created.mjs
- components/mews/sources/reservation-cancelled/reservation-cancelled.mjs
- components/mews/sources/customer-created/customer-created.mjs
- components/mews/actions/create-availability-block/create-availability-block.mjs
- components/mews/sources/company-created/company-created.mjs
- components/mews/actions/add-customer-file/add-customer-file.mjs
- components/mews/actions/cancel-reservation/cancel-reservation.mjs
- components/mews/actions/create-reservation/create-reservation.mjs
- components/mews/actions/get-rate-prices/get-rate-prices.mjs
- components/mews/package.json
- components/mews/sources/order-item-updated/order-item-updated.mjs
- components/mews/sources/bill-closed/bill-closed.mjs
- components/mews/common/utils.mjs
- components/mews/actions/fetch-reservations/fetch-reservations.mjs
- components/mews/actions/add-reservation-companion/add-reservation-companion.mjs
- components/mews/actions/update-customer/update-customer.mjs
🧰 Additional context used
🧬 Code Graph Analysis (8)
components/mews/actions/create-task/create-task.mjs (2)
components/mews/actions/add-customer-file/add-customer-file.mjs (1)
response(50-58)components/mews/actions/create-reservation/create-reservation.mjs (1)
response(118-157)
components/mews/actions/create-order/create-order.mjs (2)
components/mews/actions/add-reservation-product/add-reservation-product.mjs (1)
response(88-103)components/mews/actions/update-reservation/update-reservation.mjs (1)
response(227-331)
components/mews/actions/get-bill-pdf/get-bill-pdf.mjs (1)
components/mews/mews.app.mjs (1)
response(551-560)
components/mews/actions/fetch-order-items/fetch-order-items.mjs (4)
components/mews/actions/fetch-products/fetch-products.mjs (1)
items(66-84)components/mews/actions/fetch-customers/fetch-customers.mjs (1)
items(139-175)components/mews/actions/fetch-reservations/fetch-reservations.mjs (1)
items(228-290)components/mews/sources/common/polling.mjs (1)
items(97-109)
components/mews/actions/add-reservation-product/add-reservation-product.mjs (1)
components/mews/actions/add-reservation-companion/add-reservation-companion.mjs (1)
response(33-39)
components/mews/actions/fetch-products/fetch-products.mjs (4)
components/mews/actions/fetch-order-items/fetch-order-items.mjs (1)
items(172-219)components/mews/actions/fetch-customers/fetch-customers.mjs (1)
items(139-175)components/mews/actions/fetch-reservations/fetch-reservations.mjs (1)
items(228-290)components/mews/sources/common/polling.mjs (1)
items(97-109)
components/mews/actions/fetch-customers/fetch-customers.mjs (4)
components/mews/actions/fetch-order-items/fetch-order-items.mjs (1)
items(172-219)components/mews/actions/fetch-products/fetch-products.mjs (1)
items(66-84)components/mews/actions/fetch-reservations/fetch-reservations.mjs (1)
items(228-290)components/mews/sources/common/polling.mjs (1)
items(97-109)
components/mews/actions/update-reservation/update-reservation.mjs (2)
components/mews/actions/create-reservation/create-reservation.mjs (1)
response(118-157)components/mews/actions/update-customer/update-customer.mjs (1)
response(244-279)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Lint Code Base
- GitHub Check: Publish TypeScript components
- GitHub Check: Verify TypeScript components
🔇 Additional comments (7)
components/mews/actions/fetch-customers/fetch-customers.mjs (1)
177-179: LGTM on summary formattingGood pluralization handling.
components/mews/actions/create-task/create-task.mjs (1)
1-41: Solid new actionProps and mappings align with Mews “Add task” API; good use of propDefinitions for Department and Service Order.
components/mews/actions/get-bill-pdf/get-bill-pdf.mjs (1)
68-80: Confirm binary/base64 handling for PDF responseIf
billsGetPdfreturns base64 content and filename, ensure the response is shaped for downstream usage (e.g., expose{ fileName, contentBase64 }) and that the HTTP client doesn’t try to JSON-parse binary.If needed, consider:
- const response = await app.billsGetPdf({ + const response = await app.billsGetPdf({ $, data: { BillId: billId, BillPrintEventId: billPrintEventId, PdfTemplate: pdfTemplate, PrintReason: printReason, }, }); - $.export("summary", `Successfully retrieved PDF for bill ${billId}`); - return response; + $.export("summary", `Successfully retrieved PDF for bill ${billId}`); + // If app.billsGetPdf returns { FileName, Data } (base64), return a structured object + return { + billId, + fileName: response?.FileName ?? `bill-${billId}.pdf`, + contentBase64: response?.Data ?? response, // adjust to actual shape + };components/mews/actions/fetch-order-items/fetch-order-items.mjs (1)
221-223: LGTM on summary formattingGood pluralization handling.
components/mews/actions/update-reservation/update-reservation.mjs (1)
311-327: Good boolean gating for optional flags.Using
!== undefinedensures false is preserved while omitting truly unset values. Same for nested Options.OwnerCheckedIn. Nicely done.components/mews/mews.app.mjs (1)
511-516: New endpoints look consistent with Mews Connector API paths.
billsGetPdf,countriesGetAll,creditCardsGetAll, andavailabilityBlocksGetAllmethods follow the expected path patterns and composition with_makeRequest.Also applies to: 523-534
components/mews/actions/add-reservation-product/add-reservation-product.mjs (1)
45-56: Confirm currency requirement when overriding price.If a custom price is provided (Gross/Net), does the API require Currency to be present? If yes, make
unitAmountCurrencyrequired only when one of the amounts is provided and validate accordingly.I can add conditional validation (and mark the prop required dynamically) once you confirm the API requirement.
Also applies to: 63-72
components/mews/actions/create-availability-block/create-availability-block.mjs
Show resolved
Hide resolved
components/mews/actions/update-reservation/update-reservation.mjs
Outdated
Show resolved
Hide resolved
37d3820 to
cfa444a
Compare
cfa444a to
12da217
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
669b02f to
86c12e9
Compare
86c12e9 to
909db14
Compare
|
/approve |
WHY
Resolves #3689
Summary by CodeRabbit
New Features
Enhancements
Chores