fix(medusa): migrate cart service to typescript (#884)
* fix: migrate cart service to typescript * fix: jsdoc inventory service * fix: revert route unit test change * fix: typo * fix: revert integration test packages * fix: cleanup * fix: tests * fix: integration tests * fix: create props type guards * fix: move total field to common types
This commit is contained in:
1 parent
03ffab5d61
commit
ed04132533
17 files changed
+504
-203
No files matched your search
@@ -95,7 +95,7 @@ Object {
|
|||||||
"payment_authorized_at": null,
|
"payment_authorized_at": null,
|
||||||
"payment_id": null,
|
"payment_id": null,
|
||||||
"region_id": "test-region",
|
"region_id": "test-region",
|
||||||
"shipping_address_id": "test-shipping-address",
|
"shipping_address_id": StringMatching /\\^addr_\\*/,
|
||||||
"type": "swap",
|
"type": "swap",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
},
|
},
|
||||||
@@ -266,7 +266,7 @@ Object {
|
|||||||
"payment_authorized_at": null,
|
"payment_authorized_at": null,
|
||||||
"payment_id": null,
|
"payment_id": null,
|
||||||
"region_id": "test-region",
|
"region_id": "test-region",
|
||||||
"shipping_address_id": "test-shipping-address",
|
"shipping_address_id": StringMatching /\\^addr_\\*/,
|
||||||
"type": "swap",
|
"type": "swap",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -137,6 +137,7 @@ describe("/store/carts", () => {
|
|||||||
type: "swap",
|
type: "swap",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
|
shipping_address_id: expect.stringMatching(/^addr_*/),
|
||||||
metadata: {
|
metadata: {
|
||||||
swap_id: expect.stringMatching(/^swap_*/),
|
swap_id: expect.stringMatching(/^swap_*/),
|
||||||
},
|
},
|
||||||
@@ -220,6 +221,7 @@ describe("/store/carts", () => {
|
|||||||
cart: {
|
cart: {
|
||||||
id: expect.stringMatching(/^cart_*/),
|
id: expect.stringMatching(/^cart_*/),
|
||||||
billing_address_id: "test-billing-address",
|
billing_address_id: "test-billing-address",
|
||||||
|
shipping_address_id: expect.stringMatching(/^addr_*/),
|
||||||
type: "swap",
|
type: "swap",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export const MedusaErrorTypes = {
|
|||||||
INVALID_DATA: "invalid_data",
|
INVALID_DATA: "invalid_data",
|
||||||
NOT_FOUND: "not_found",
|
NOT_FOUND: "not_found",
|
||||||
NOT_ALLOWED: "not_allowed",
|
NOT_ALLOWED: "not_allowed",
|
||||||
|
UNEXPECTED_STATE: "unexpected_state",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MedusaErrorCodes = {
|
export const MedusaErrorCodes = {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Router } from "express"
|
import { Router } from "express"
|
||||||
import { DraftOrder, Order } from "../../../.."
|
import { DraftOrder, Order, Cart } from "../../../.."
|
||||||
import middlewares from "../../../middlewares"
|
import middlewares from "../../../middlewares"
|
||||||
import { DeleteResponse, PaginatedResponse } from "../../../../types/common"
|
import { DeleteResponse, PaginatedResponse } from "../../../../types/common"
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ export const defaultAdminDraftOrdersCartRelations = [
|
|||||||
"discounts.rule",
|
"discounts.rule",
|
||||||
]
|
]
|
||||||
|
|
||||||
export const defaultAdminDraftOrdersCartFields = [
|
export const defaultAdminDraftOrdersCartFields: (keyof Cart)[] = [
|
||||||
"subtotal",
|
"subtotal",
|
||||||
"tax_total",
|
"tax_total",
|
||||||
"shipping_total",
|
"shipping_total",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
defaultAdminDraftOrdersFields,
|
defaultAdminDraftOrdersFields,
|
||||||
} from "."
|
} from "."
|
||||||
import { DraftOrder } from "../../../.."
|
import { DraftOrder } from "../../../.."
|
||||||
|
import { LineItemUpdate } from "../../../../types/cart"
|
||||||
import { CartService, DraftOrderService } from "../../../../services"
|
import { CartService, DraftOrderService } from "../../../../services"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
/**
|
/**
|
||||||
@@ -112,15 +113,6 @@ export default async (req, res) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
class LineItemUpdate {
|
|
||||||
title?: string
|
|
||||||
unit_price?: number
|
|
||||||
quantity?: number
|
|
||||||
metadata?: object = {}
|
|
||||||
region_id?: string
|
|
||||||
variant_id?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export class AdminPostDraftOrdersDraftOrderLineItemsItemReq {
|
export class AdminPostDraftOrdersDraftOrderLineItemsItemReq {
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import {
|
|||||||
SwapService,
|
SwapService,
|
||||||
} from "../../../../services"
|
} from "../../../../services"
|
||||||
|
|
||||||
|
import { Order } from "../../../../models/order"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [post] /carts/{id}/complete
|
* @oas [post] /carts/{id}/complete
|
||||||
* summary: "Complete a Cart"
|
* summary: "Complete a Cart"
|
||||||
@@ -144,7 +146,7 @@ export default async (req, res) => {
|
|||||||
relations: ["payment", "payment_sessions"],
|
relations: ["payment", "payment_sessions"],
|
||||||
})
|
})
|
||||||
|
|
||||||
let order
|
let order: Order
|
||||||
|
|
||||||
// If cart is part of swap, we register swap as complete
|
// If cart is part of swap, we register swap as complete
|
||||||
switch (cart.type) {
|
switch (cart.type) {
|
||||||
@@ -183,6 +185,15 @@ export default async (req, res) => {
|
|||||||
}
|
}
|
||||||
// case "payment_link":
|
// case "payment_link":
|
||||||
default: {
|
default: {
|
||||||
|
if (typeof cart.total === "undefined") {
|
||||||
|
return {
|
||||||
|
response_code: 500,
|
||||||
|
response_body: {
|
||||||
|
message: "Unexpected state",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!cart.payment && cart.total > 0) {
|
if (!cart.payment && cart.total > 0) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ import {
|
|||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import reqIp from "request-ip"
|
import reqIp from "request-ip"
|
||||||
import { EntityManager } from "typeorm"
|
import { EntityManager } from "typeorm"
|
||||||
|
|
||||||
import { defaultStoreCartFields, defaultStoreCartRelations } from "."
|
import { defaultStoreCartFields, defaultStoreCartRelations } from "."
|
||||||
import { CartService, LineItemService } from "../../../../services"
|
import { CartService, LineItemService } from "../../../../services"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
import { AddressPayload } from "../../../../types/common"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [post] /carts
|
* @oas [post] /carts
|
||||||
@@ -74,8 +76,11 @@ export default async (req, res) => {
|
|||||||
|
|
||||||
await entityManager.transaction(async (manager) => {
|
await entityManager.transaction(async (manager) => {
|
||||||
// Add a default region if no region has been specified
|
// Add a default region if no region has been specified
|
||||||
let regionId = validated.region_id
|
let regionId: string
|
||||||
if (!validated.region_id) {
|
|
||||||
|
if (typeof validated.region_id !== "undefined") {
|
||||||
|
regionId = validated.region_id
|
||||||
|
} else {
|
||||||
const regionService = req.scope.resolve("regionService")
|
const regionService = req.scope.resolve("regionService")
|
||||||
const regions = await regionService.withTransaction(manager).list({})
|
const regions = await regionService.withTransaction(manager).list({})
|
||||||
|
|
||||||
@@ -90,11 +95,11 @@ export default async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const toCreate: {
|
const toCreate: {
|
||||||
region_id: string | undefined
|
region_id: string
|
||||||
context: object
|
context: object
|
||||||
customer_id?: string
|
customer_id?: string
|
||||||
email?: string
|
email?: string
|
||||||
shipping_address?: object
|
shipping_address?: Partial<AddressPayload>
|
||||||
} = {
|
} = {
|
||||||
region_id: regionId,
|
region_id: regionId,
|
||||||
context: {
|
context: {
|
||||||
@@ -121,7 +126,7 @@ export default async (req, res) => {
|
|||||||
let cart = await cartService.withTransaction(manager).create(toCreate)
|
let cart = await cartService.withTransaction(manager).create(toCreate)
|
||||||
if (validated.items) {
|
if (validated.items) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
validated.items.map(async i => {
|
validated.items.map(async (i) => {
|
||||||
const lineItem = await lineItemService
|
const lineItem = await lineItemService
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.generate(i.variant_id, regionId, i.quantity)
|
.generate(i.variant_id, regionId, i.quantity)
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export default (app, container) => {
|
|||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultStoreCartFields = [
|
export const defaultStoreCartFields: (keyof Cart)[] = [
|
||||||
"subtotal",
|
"subtotal",
|
||||||
"tax_total",
|
"tax_total",
|
||||||
"shipping_total",
|
"shipping_total",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
import { defaultStoreCartFields, defaultStoreCartRelations } from "."
|
import { defaultStoreCartFields, defaultStoreCartRelations } from "."
|
||||||
import { CartService } from "../../../../services"
|
import { CartService } from "../../../../services"
|
||||||
import { AddressPayload } from "../../../../types/common"
|
import { AddressPayload } from "../../../../types/common"
|
||||||
|
import { CartUpdateProps } from "../../../../types/cart"
|
||||||
import { IsType } from "../../../../utils/validators/is-type"
|
import { IsType } from "../../../../utils/validators/is-type"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
@@ -87,7 +88,25 @@ export default async (req, res) => {
|
|||||||
const cartService: CartService = req.scope.resolve("cartService")
|
const cartService: CartService = req.scope.resolve("cartService")
|
||||||
|
|
||||||
// Update the cart
|
// Update the cart
|
||||||
await cartService.update(id, validated)
|
const { shipping_address, billing_address, ...rest } = validated
|
||||||
|
|
||||||
|
const toUpdate: CartUpdateProps = {
|
||||||
|
...rest,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof shipping_address === "string") {
|
||||||
|
toUpdate.shipping_address_id = shipping_address
|
||||||
|
} else {
|
||||||
|
toUpdate.shipping_address = shipping_address
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof billing_address === "string") {
|
||||||
|
toUpdate.billing_address_id = billing_address
|
||||||
|
} else {
|
||||||
|
toUpdate.billing_address = billing_address
|
||||||
|
}
|
||||||
|
|
||||||
|
await cartService.update(id, toUpdate)
|
||||||
|
|
||||||
// If the cart has payment sessions update these
|
// If the cart has payment sessions update these
|
||||||
const updated = await cartService.retrieve(id, {
|
const updated = await cartService.retrieve(id, {
|
||||||
|
|||||||
@@ -50,46 +50,46 @@ export class Address {
|
|||||||
id: string
|
id: string
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column({ nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
customer_id: string
|
customer_id: string | null
|
||||||
|
|
||||||
@ManyToOne(() => Customer)
|
@ManyToOne(() => Customer)
|
||||||
@JoinColumn({ name: "customer_id" })
|
@JoinColumn({ name: "customer_id" })
|
||||||
customer: Customer
|
customer: Customer | null
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
company: string
|
company: string | null
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
first_name: string
|
first_name: string | null
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
last_name: string
|
last_name: string | null
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
address_1: string
|
address_1: string | null
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
address_2: string
|
address_2: string | null
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
city: string
|
city: string | null
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
country_code: string
|
country_code: string | null
|
||||||
|
|
||||||
@ManyToOne(() => Country)
|
@ManyToOne(() => Country)
|
||||||
@JoinColumn({ name: "country_code", referencedColumnName: "iso_2" })
|
@JoinColumn({ name: "country_code", referencedColumnName: "iso_2" })
|
||||||
country: Country
|
country: Country | null
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
province: string
|
province: string | null
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
postal_code: string
|
postal_code: string | null
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
phone: string
|
phone: string | null
|
||||||
|
|
||||||
@CreateDateColumn({ type: resolveDbType("timestamptz") })
|
@CreateDateColumn({ type: resolveDbType("timestamptz") })
|
||||||
created_at: Date
|
created_at: Date
|
||||||
@@ -98,7 +98,7 @@ export class Address {
|
|||||||
updated_at: Date
|
updated_at: Date
|
||||||
|
|
||||||
@DeleteDateColumn({ type: resolveDbType("timestamptz") })
|
@DeleteDateColumn({ type: resolveDbType("timestamptz") })
|
||||||
deleted_at: Date
|
deleted_at: Date | null
|
||||||
|
|
||||||
@DbAwareColumn({ type: "jsonb", nullable: true })
|
@DbAwareColumn({ type: "jsonb", nullable: true })
|
||||||
metadata: any
|
metadata: any
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ export class Cart {
|
|||||||
cascade: ["insert", "remove", "soft-remove"],
|
cascade: ["insert", "remove", "soft-remove"],
|
||||||
})
|
})
|
||||||
@JoinColumn({ name: "shipping_address_id" })
|
@JoinColumn({ name: "shipping_address_id" })
|
||||||
shipping_address: Address
|
shipping_address: Address | null
|
||||||
|
|
||||||
@OneToMany(() => LineItem, (lineItem) => lineItem.cart, {
|
@OneToMany(() => LineItem, (lineItem) => lineItem.cart, {
|
||||||
cascade: ["insert", "remove"],
|
cascade: ["insert", "remove"],
|
||||||
@@ -172,7 +172,7 @@ export class Cart {
|
|||||||
referencedColumnName: "id",
|
referencedColumnName: "id",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
discounts: Discount
|
discounts: Discount[]
|
||||||
|
|
||||||
@ManyToMany(() => GiftCard)
|
@ManyToMany(() => GiftCard)
|
||||||
@JoinTable({
|
@JoinTable({
|
||||||
@@ -186,7 +186,7 @@ export class Cart {
|
|||||||
referencedColumnName: "id",
|
referencedColumnName: "id",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
gift_cards: GiftCard
|
gift_cards: GiftCard[]
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
@@ -196,7 +196,7 @@ export class Cart {
|
|||||||
@JoinColumn({ name: "customer_id" })
|
@JoinColumn({ name: "customer_id" })
|
||||||
customer: Customer
|
customer: Customer
|
||||||
|
|
||||||
payment_session: PaymentSession
|
payment_session: PaymentSession | null
|
||||||
|
|
||||||
@OneToMany(() => PaymentSession, (paymentSession) => paymentSession.cart, {
|
@OneToMany(() => PaymentSession, (paymentSession) => paymentSession.cart, {
|
||||||
cascade: true,
|
cascade: true,
|
||||||
@@ -217,7 +217,7 @@ export class Cart {
|
|||||||
shipping_methods: ShippingMethod[]
|
shipping_methods: ShippingMethod[]
|
||||||
|
|
||||||
@DbAwareColumn({ type: "enum", enum: CartType, default: "default" })
|
@DbAwareColumn({ type: "enum", enum: CartType, default: "default" })
|
||||||
type: boolean
|
type: CartType
|
||||||
|
|
||||||
@Column({ type: resolveDbType("timestamptz"), nullable: true })
|
@Column({ type: resolveDbType("timestamptz"), nullable: true })
|
||||||
completed_at: Date
|
completed_at: Date
|
||||||
@@ -243,15 +243,14 @@ export class Cart {
|
|||||||
@DbAwareColumn({ type: "jsonb", nullable: true })
|
@DbAwareColumn({ type: "jsonb", nullable: true })
|
||||||
context: any
|
context: any
|
||||||
|
|
||||||
// Total fields
|
shipping_total?: number
|
||||||
shipping_total: number
|
discount_total?: number
|
||||||
discount_total: number
|
tax_total?: number
|
||||||
tax_total: number
|
refunded_total?: number
|
||||||
refunded_total: number
|
total?: number
|
||||||
total: number
|
subtotal?: number
|
||||||
subtotal: number
|
refundable_amount?: number
|
||||||
refundable_amount: number
|
gift_card_total?: number
|
||||||
gift_card_total: number
|
|
||||||
|
|
||||||
@BeforeInsert()
|
@BeforeInsert()
|
||||||
private beforeInsert(): undefined | void {
|
private beforeInsert(): undefined | void {
|
||||||
|
|||||||
@@ -32,10 +32,7 @@ export class PaymentSession {
|
|||||||
@Column()
|
@Column()
|
||||||
cart_id: string
|
cart_id: string
|
||||||
|
|
||||||
@ManyToOne(
|
@ManyToOne(() => Cart, (cart) => cart.payment_sessions)
|
||||||
() => Cart,
|
|
||||||
cart => cart.payment_sessions
|
|
||||||
)
|
|
||||||
@JoinColumn({ name: "cart_id" })
|
@JoinColumn({ name: "cart_id" })
|
||||||
cart: Cart
|
cart: Cart
|
||||||
|
|
||||||
@@ -43,8 +40,8 @@ export class PaymentSession {
|
|||||||
@Column()
|
@Column()
|
||||||
provider_id: string
|
provider_id: string
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ type: "boolean", nullable: true })
|
||||||
is_selected: boolean
|
is_selected: boolean | null
|
||||||
|
|
||||||
@DbAwareColumn({ type: "enum", enum: PaymentSessionStatus })
|
@DbAwareColumn({ type: "enum", enum: PaymentSessionStatus })
|
||||||
status: string
|
status: string
|
||||||
|
|||||||
@@ -1,7 +1,64 @@
|
|||||||
import _ from "lodash"
|
import _ from "lodash"
|
||||||
|
import { EntityManager, DeepPartial } from "typeorm"
|
||||||
import { MedusaError, Validator } from "medusa-core-utils"
|
import { MedusaError, Validator } from "medusa-core-utils"
|
||||||
import { BaseService } from "medusa-interfaces"
|
import { BaseService } from "medusa-interfaces"
|
||||||
|
|
||||||
|
import { ShippingMethodRepository } from "../repositories/shipping-method"
|
||||||
|
import { CartRepository } from "../repositories/cart"
|
||||||
|
import { AddressRepository } from "../repositories/address"
|
||||||
|
import { PaymentSessionRepository } from "../repositories/payment-session"
|
||||||
|
|
||||||
|
import { Address } from "../models/address"
|
||||||
|
import { Discount } from "../models/discount"
|
||||||
|
import { Cart } from "../models/cart"
|
||||||
|
import { Customer } from "../models/customer"
|
||||||
|
import { LineItem } from "../models/line-item"
|
||||||
|
import { ShippingMethod } from "../models/shipping-method"
|
||||||
|
import { CustomShippingOption } from "../models/custom-shipping-option"
|
||||||
|
|
||||||
|
import { TotalField, FindConfig } from "../types/common"
|
||||||
|
import {
|
||||||
|
FilterableCartProps,
|
||||||
|
LineItemUpdate,
|
||||||
|
CartUpdateProps,
|
||||||
|
CartCreateProps,
|
||||||
|
} from "../types/cart"
|
||||||
|
|
||||||
|
import EventBusService from "./event-bus"
|
||||||
|
import ProductVariantService from "./product-variant"
|
||||||
|
import ProductService from "./product"
|
||||||
|
import RegionService from "./region"
|
||||||
|
import LineItemService from "./line-item"
|
||||||
|
import PaymentProviderService from "./payment-provider"
|
||||||
|
import ShippingOptionService from "./shipping-option"
|
||||||
|
import CustomerService from "./customer"
|
||||||
|
import DiscountService from "./discount"
|
||||||
|
import GiftCardService from "./gift-card"
|
||||||
|
import TotalsService from "./totals"
|
||||||
|
import InventoryService from "./inventory"
|
||||||
|
import CustomShippingOptionService from "./custom-shipping-option"
|
||||||
|
|
||||||
|
type CartConstructorProps = {
|
||||||
|
manager: EntityManager
|
||||||
|
cartRepository: typeof CartRepository
|
||||||
|
shippingMethodRepository: typeof ShippingMethodRepository
|
||||||
|
addressRepository: typeof AddressRepository
|
||||||
|
paymentSessionRepository: typeof PaymentSessionRepository
|
||||||
|
eventBusService: EventBusService
|
||||||
|
paymentProviderService: PaymentProviderService
|
||||||
|
productService: ProductService
|
||||||
|
productVariantService: ProductVariantService
|
||||||
|
regionService: RegionService
|
||||||
|
lineItemService: LineItemService
|
||||||
|
shippingOptionService: ShippingOptionService
|
||||||
|
customerService: CustomerService
|
||||||
|
discountService: DiscountService
|
||||||
|
giftCardService: GiftCardService
|
||||||
|
totalsService: TotalsService
|
||||||
|
inventoryService: InventoryService
|
||||||
|
customShippingOptionService: CustomShippingOptionService
|
||||||
|
}
|
||||||
|
|
||||||
/* Provides layer to manipulate carts.
|
/* Provides layer to manipulate carts.
|
||||||
* @implements BaseService
|
* @implements BaseService
|
||||||
*/
|
*/
|
||||||
@@ -12,6 +69,25 @@ class CartService extends BaseService {
|
|||||||
UPDATED: "cart.updated",
|
UPDATED: "cart.updated",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private manager_: EntityManager
|
||||||
|
private shippingMethodRepository_: typeof ShippingMethodRepository
|
||||||
|
private cartRepository_: typeof CartRepository
|
||||||
|
private eventBus_: EventBusService
|
||||||
|
private productVariantService_: ProductVariantService
|
||||||
|
private productService_: ProductService
|
||||||
|
private regionService_: RegionService
|
||||||
|
private lineItemService_: LineItemService
|
||||||
|
private paymentProviderService_: PaymentProviderService
|
||||||
|
private customerService_: CustomerService
|
||||||
|
private shippingOptionService_: ShippingOptionService
|
||||||
|
private discountService_: DiscountService
|
||||||
|
private giftCardService_: GiftCardService
|
||||||
|
private totalsService_: TotalsService
|
||||||
|
private addressRepository_: typeof AddressRepository
|
||||||
|
private paymentSessionRepository_: typeof PaymentSessionRepository
|
||||||
|
private inventoryService_: InventoryService
|
||||||
|
private customShippingOptionService_: CustomShippingOptionService
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
manager,
|
manager,
|
||||||
cartRepository,
|
cartRepository,
|
||||||
@@ -31,7 +107,7 @@ class CartService extends BaseService {
|
|||||||
paymentSessionRepository,
|
paymentSessionRepository,
|
||||||
inventoryService,
|
inventoryService,
|
||||||
customShippingOptionService,
|
customShippingOptionService,
|
||||||
}) {
|
}: CartConstructorProps) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
/** @private @const {EntityManager} */
|
/** @private @const {EntityManager} */
|
||||||
@@ -89,7 +165,7 @@ class CartService extends BaseService {
|
|||||||
this.customShippingOptionService_ = customShippingOptionService
|
this.customShippingOptionService_ = customShippingOptionService
|
||||||
}
|
}
|
||||||
|
|
||||||
withTransaction(transactionManager) {
|
withTransaction(transactionManager: EntityManager): CartService {
|
||||||
if (!transactionManager) {
|
if (!transactionManager) {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
@@ -139,7 +215,9 @@ class CartService extends BaseService {
|
|||||||
* @typedef {LineItemContent[]} LineItemContentArray
|
* @typedef {LineItemContent[]} LineItemContentArray
|
||||||
*/
|
*/
|
||||||
|
|
||||||
transformQueryForTotals_(config) {
|
transformQueryForTotals_(
|
||||||
|
config: FindConfig<Cart>
|
||||||
|
): FindConfig<Cart> & { totalsToSelect: TotalField[] } {
|
||||||
let { select, relations } = config
|
let { select, relations } = config
|
||||||
|
|
||||||
if (!select) {
|
if (!select) {
|
||||||
@@ -159,7 +237,9 @@ class CartService extends BaseService {
|
|||||||
"total",
|
"total",
|
||||||
]
|
]
|
||||||
|
|
||||||
const totalsToSelect = select.filter((v) => totalFields.includes(v))
|
const totalsToSelect = select.filter((v) =>
|
||||||
|
totalFields.includes(v)
|
||||||
|
) as TotalField[]
|
||||||
if (totalsToSelect.length > 0) {
|
if (totalsToSelect.length > 0) {
|
||||||
const relationSet = new Set(relations)
|
const relationSet = new Set(relations)
|
||||||
relationSet.add("items")
|
relationSet.add("items")
|
||||||
@@ -184,26 +264,40 @@ class CartService extends BaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async decorateTotals_(cart, totalsFields = []) {
|
async decorateTotals_(
|
||||||
if (totalsFields.includes("shipping_total")) {
|
cart: Cart,
|
||||||
cart.shipping_total = await this.totalsService_.getShippingTotal(cart)
|
totalsToSelect: TotalField[]
|
||||||
|
): Promise<Cart> {
|
||||||
|
const totals: { [K in TotalField]?: number } = {}
|
||||||
|
|
||||||
|
for (const key of totalsToSelect) {
|
||||||
|
switch (key) {
|
||||||
|
case "total": {
|
||||||
|
totals.total = await this.totalsService_.getTotal(cart)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if (totalsFields.includes("discount_total")) {
|
case "shipping_total": {
|
||||||
cart.discount_total = await this.totalsService_.getDiscountTotal(cart)
|
totals.shipping_total = this.totalsService_.getShippingTotal(cart)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if (totalsFields.includes("tax_total")) {
|
case "discount_total":
|
||||||
cart.tax_total = await this.totalsService_.getTaxTotal(cart)
|
totals.discount_total = this.totalsService_.getDiscountTotal(cart)
|
||||||
|
break
|
||||||
|
case "tax_total":
|
||||||
|
totals.tax_total = await this.totalsService_.getTaxTotal(cart)
|
||||||
|
break
|
||||||
|
case "gift_card_total":
|
||||||
|
totals.gift_card_total = this.totalsService_.getGiftCardTotal(cart)
|
||||||
|
break
|
||||||
|
case "subtotal":
|
||||||
|
totals.subtotal = this.totalsService_.getSubtotal(cart)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if (totalsFields.includes("gift_card_total")) {
|
|
||||||
cart.gift_card_total = await this.totalsService_.getGiftCardTotal(cart)
|
|
||||||
}
|
}
|
||||||
if (totalsFields.includes("subtotal")) {
|
|
||||||
cart.subtotal = await this.totalsService_.getSubtotal(cart)
|
return Object.assign(cart, totals)
|
||||||
}
|
|
||||||
if (totalsFields.includes("total")) {
|
|
||||||
cart.total = await this.totalsService_.getTotal(cart)
|
|
||||||
}
|
|
||||||
return cart
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -211,22 +305,14 @@ class CartService extends BaseService {
|
|||||||
* @param {Object} config - config object
|
* @param {Object} config - config object
|
||||||
* @return {Promise} the result of the find operation
|
* @return {Promise} the result of the find operation
|
||||||
*/
|
*/
|
||||||
list(selector, config = {}) {
|
async list(
|
||||||
|
selector: FilterableCartProps,
|
||||||
|
config: FindConfig<Cart> = {}
|
||||||
|
): Promise<Cart[]> {
|
||||||
const cartRepo = this.manager_.getCustomRepository(this.cartRepository_)
|
const cartRepo = this.manager_.getCustomRepository(this.cartRepository_)
|
||||||
|
|
||||||
const query = {
|
const query = this.buildQuery_(selector, config)
|
||||||
where: selector,
|
return await cartRepo.find(query)
|
||||||
}
|
|
||||||
|
|
||||||
if (config.select) {
|
|
||||||
query.select = config.select
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.relations) {
|
|
||||||
query.relations = config.relations
|
|
||||||
}
|
|
||||||
|
|
||||||
return cartRepo.find(query)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -235,16 +321,20 @@ class CartService extends BaseService {
|
|||||||
* @param {Object} options - the options to get a cart
|
* @param {Object} options - the options to get a cart
|
||||||
* @return {Promise<Cart>} the cart document.
|
* @return {Promise<Cart>} the cart document.
|
||||||
*/
|
*/
|
||||||
async retrieve(cartId, options = {}) {
|
async retrieve(
|
||||||
|
cartId: string,
|
||||||
|
options: FindConfig<Cart> = {}
|
||||||
|
): Promise<Cart> {
|
||||||
const cartRepo = this.manager_.getCustomRepository(this.cartRepository_)
|
const cartRepo = this.manager_.getCustomRepository(this.cartRepository_)
|
||||||
const validatedId = this.validateId_(cartId)
|
const validatedId = this.validateId_(cartId)
|
||||||
|
|
||||||
const { select, relations, totalsToSelect } =
|
const { select, relations, totalsToSelect } =
|
||||||
this.transformQueryForTotals_(options)
|
this.transformQueryForTotals_(options)
|
||||||
|
|
||||||
const query = {
|
const query = this.buildQuery_(
|
||||||
where: { id: validatedId },
|
{ id: validatedId },
|
||||||
}
|
{ ...options, select, relations }
|
||||||
|
)
|
||||||
|
|
||||||
if (relations && relations.length > 0) {
|
if (relations && relations.length > 0) {
|
||||||
query.relations = relations
|
query.relations = relations
|
||||||
@@ -252,10 +342,13 @@ class CartService extends BaseService {
|
|||||||
|
|
||||||
if (select && select.length > 0) {
|
if (select && select.length > 0) {
|
||||||
query.select = select
|
query.select = select
|
||||||
|
} else {
|
||||||
|
delete query.select
|
||||||
}
|
}
|
||||||
|
|
||||||
const rels = query.relations
|
const rels = query.relations
|
||||||
delete query.relations
|
delete query.relations
|
||||||
|
|
||||||
const raw = await cartRepo.findOneWithRelations(rels, query)
|
const raw = await cartRepo.findOneWithRelations(rels, query)
|
||||||
|
|
||||||
if (!raw) {
|
if (!raw) {
|
||||||
@@ -265,8 +358,7 @@ class CartService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const cart = await this.decorateTotals_(raw, totalsToSelect)
|
return await this.decorateTotals_(raw, totalsToSelect)
|
||||||
return cart
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -274,10 +366,11 @@ class CartService extends BaseService {
|
|||||||
* @param {Object} data - the data to create the cart with
|
* @param {Object} data - the data to create the cart with
|
||||||
* @return {Promise} the result of the create operation
|
* @return {Promise} the result of the create operation
|
||||||
*/
|
*/
|
||||||
async create(data) {
|
async create(data: CartCreateProps): Promise<Cart> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
||||||
const addressRepo = manager.getCustomRepository(this.addressRepository_)
|
const addressRepo = manager.getCustomRepository(this.addressRepository_)
|
||||||
|
|
||||||
const { region_id } = data
|
const { region_id } = data
|
||||||
if (!region_id) {
|
if (!region_id) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
@@ -289,26 +382,35 @@ class CartService extends BaseService {
|
|||||||
const region = await this.regionService_.retrieve(region_id, {
|
const region = await this.regionService_.retrieve(region_id, {
|
||||||
relations: ["countries"],
|
relations: ["countries"],
|
||||||
})
|
})
|
||||||
|
|
||||||
const regCountries = region.countries.map(({ iso_2 }) => iso_2)
|
const regCountries = region.countries.map(({ iso_2 }) => iso_2)
|
||||||
|
|
||||||
if (data.email) {
|
const toCreate: DeepPartial<Cart> = {}
|
||||||
|
toCreate.region_id = region.id
|
||||||
|
|
||||||
|
if (typeof data.email !== "undefined") {
|
||||||
const customer = await this.createOrFetchUserFromEmail_(data.email)
|
const customer = await this.createOrFetchUserFromEmail_(data.email)
|
||||||
data.customer = customer
|
toCreate.customer = customer
|
||||||
data.customer_id = customer.id
|
toCreate.customer_id = customer.id
|
||||||
data.email = customer.email
|
toCreate.email = customer.email
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.shipping_address_id) {
|
if (typeof data.shipping_address_id !== "undefined") {
|
||||||
const addr = await addressRepo.findOne(data.shipping_address_id)
|
const addr = await addressRepo.findOne(data.shipping_address_id)
|
||||||
data.shipping_address = addr
|
if (addr && !regCountries.includes(addr.country_code)) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_ALLOWED,
|
||||||
|
"Shipping country not in region"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
toCreate.shipping_address = addr
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data.shipping_address) {
|
if (!data.shipping_address) {
|
||||||
if (region.countries.length === 1) {
|
if (region.countries.length === 1) {
|
||||||
// Preselect the country if the region only has 1
|
// Preselect the country if the region only has 1
|
||||||
// and create address entity
|
// and create address entity
|
||||||
data.shipping_address = addressRepo.create({
|
toCreate.shipping_address = addressRepo.create({
|
||||||
country_code: regCountries[0],
|
country_code: regCountries[0],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -319,14 +421,26 @@ class CartService extends BaseService {
|
|||||||
"Shipping country not in region"
|
"Shipping country not in region"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toCreate.shipping_address = data.shipping_address
|
||||||
}
|
}
|
||||||
|
|
||||||
const toCreate = {
|
const remainingFields: (keyof Cart)[] = [
|
||||||
...data,
|
"billing_address_id",
|
||||||
region_id: region.id,
|
"context",
|
||||||
|
"type",
|
||||||
|
"metadata",
|
||||||
|
"discounts",
|
||||||
|
"gift_cards",
|
||||||
|
]
|
||||||
|
|
||||||
|
for (const k of remainingFields) {
|
||||||
|
if (typeof data[k] !== "undefined") {
|
||||||
|
toCreate[k] = data[k]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const inProgress = await cartRepo.create(toCreate)
|
const inProgress = cartRepo.create(toCreate)
|
||||||
const result = await cartRepo.save(inProgress)
|
const result = await cartRepo.save(inProgress)
|
||||||
await this.eventBus_
|
await this.eventBus_
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
@@ -343,8 +457,8 @@ class CartService extends BaseService {
|
|||||||
* @param {LineItem} lineItemId - the line item to remove.
|
* @param {LineItem} lineItemId - the line item to remove.
|
||||||
* @return {Promise} the result of the update operation
|
* @return {Promise} the result of the update operation
|
||||||
*/
|
*/
|
||||||
async removeLineItem(cartId, lineItemId) {
|
async removeLineItem(cartId: string, lineItemId: string): Promise<Cart> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
relations: [
|
relations: [
|
||||||
"items",
|
"items",
|
||||||
@@ -395,7 +509,10 @@ class CartService extends BaseService {
|
|||||||
* @param {LineItem} lineItem - the line item
|
* @param {LineItem} lineItem - the line item
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
validateLineItemShipping_(shippingMethods, lineItem) {
|
validateLineItemShipping_(
|
||||||
|
shippingMethods: ShippingMethod[],
|
||||||
|
lineItem: LineItem
|
||||||
|
): boolean {
|
||||||
if (!lineItem.variant_id) {
|
if (!lineItem.variant_id) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -422,8 +539,8 @@ class CartService extends BaseService {
|
|||||||
* @param {LineItem} lineItem - the line item to add.
|
* @param {LineItem} lineItem - the line item to add.
|
||||||
* @return {Promise} the result of the update operation
|
* @return {Promise} the result of the update operation
|
||||||
*/
|
*/
|
||||||
async addLineItem(cartId, lineItem) {
|
async addLineItem(cartId: string, lineItem: LineItem): Promise<Cart> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
relations: [
|
relations: [
|
||||||
"shipping_methods",
|
"shipping_methods",
|
||||||
@@ -434,12 +551,13 @@ class CartService extends BaseService {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
let currentItem
|
let currentItem: LineItem | undefined
|
||||||
if (lineItem.should_merge) {
|
if (lineItem.should_merge) {
|
||||||
currentItem = cart.items.find((line) => {
|
currentItem = cart.items.find((line) => {
|
||||||
if (line.should_merge && line.variant_id === lineItem.variant_id) {
|
if (line.should_merge && line.variant_id === lineItem.variant_id) {
|
||||||
return _.isEqual(line.metadata, lineItem.metadata)
|
return _.isEqual(line.metadata, lineItem.metadata)
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -501,8 +619,12 @@ class CartService extends BaseService {
|
|||||||
* include an id field.
|
* include an id field.
|
||||||
* @return {Promise} the result of the update operation
|
* @return {Promise} the result of the update operation
|
||||||
*/
|
*/
|
||||||
async updateLineItem(cartId, lineItemId, lineItemUpdate) {
|
async updateLineItem(
|
||||||
return this.atomicPhase_(async (manager) => {
|
cartId: string,
|
||||||
|
lineItemId: string,
|
||||||
|
lineItemUpdate: LineItemUpdate
|
||||||
|
): Promise<Cart> {
|
||||||
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
relations: ["items", "payment_sessions"],
|
relations: ["items", "payment_sessions"],
|
||||||
})
|
})
|
||||||
@@ -550,7 +672,7 @@ class CartService extends BaseService {
|
|||||||
* @param {Cart} cart - the the cart to adjust free shipping for
|
* @param {Cart} cart - the the cart to adjust free shipping for
|
||||||
* @param {boolean} shouldAdd - flag to indicate, if we should add or remove
|
* @param {boolean} shouldAdd - flag to indicate, if we should add or remove
|
||||||
*/
|
*/
|
||||||
async adjustFreeShipping_(cart, shouldAdd) {
|
async adjustFreeShipping_(cart: Cart, shouldAdd: boolean): Promise<void> {
|
||||||
if (cart.shipping_methods?.length) {
|
if (cart.shipping_methods?.length) {
|
||||||
// if any free shipping discounts, we ensure to update shipping method amount
|
// if any free shipping discounts, we ensure to update shipping method amount
|
||||||
if (shouldAdd) {
|
if (shouldAdd) {
|
||||||
@@ -585,8 +707,8 @@ class CartService extends BaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(cartId, update) {
|
async update(cartId: string, update: CartUpdateProps): Promise<Cart> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
select: [
|
select: [
|
||||||
@@ -613,16 +735,16 @@ class CartService extends BaseService {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
if ("region_id" in update) {
|
if (typeof update.region_id !== "undefined") {
|
||||||
const countryCode =
|
const countryCode =
|
||||||
update.country_code || update.shipping_address?.country_code
|
(update.country_code || update.shipping_address?.country_code) ?? null
|
||||||
await this.setRegion_(cart, update.region_id, countryCode)
|
await this.setRegion_(cart, update.region_id, countryCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("customer_id" in update) {
|
if (typeof update.customer_id !== "undefined") {
|
||||||
await this.updateCustomerId_(cart, update.customer_id)
|
await this.updateCustomerId_(cart, update.customer_id)
|
||||||
} else {
|
} else {
|
||||||
if ("email" in update) {
|
if (typeof update.email !== "undefined") {
|
||||||
const customer = await this.createOrFetchUserFromEmail_(update.email)
|
const customer = await this.createOrFetchUserFromEmail_(update.email)
|
||||||
cart.customer = customer
|
cart.customer = customer
|
||||||
cart.customer_id = customer.id
|
cart.customer_id = customer.id
|
||||||
@@ -632,16 +754,32 @@ class CartService extends BaseService {
|
|||||||
|
|
||||||
const addrRepo = manager.getCustomRepository(this.addressRepository_)
|
const addrRepo = manager.getCustomRepository(this.addressRepository_)
|
||||||
if ("shipping_address_id" in update || "shipping_address" in update) {
|
if ("shipping_address_id" in update || "shipping_address" in update) {
|
||||||
const address = update.shipping_address_id || update.shipping_address
|
let address: string | Partial<Address> | undefined
|
||||||
|
if (typeof update.shipping_address_id !== "undefined") {
|
||||||
|
address = update.shipping_address_id
|
||||||
|
} else if (typeof update.shipping_address !== "undefined") {
|
||||||
|
address = update.shipping_address
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof address !== "undefined") {
|
||||||
await this.updateShippingAddress_(cart, address, addrRepo)
|
await this.updateShippingAddress_(cart, address, addrRepo)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ("billing_address_id" in update || "billing_address" in update) {
|
if ("billing_address_id" in update || "billing_address" in update) {
|
||||||
const address = update.billing_address_id || update.billing_address
|
let address: string | Partial<Address> | undefined
|
||||||
await this.updateBillingAddress_(cart, address, addrRepo)
|
if (typeof update.billing_address_id !== "undefined") {
|
||||||
|
address = update.billing_address_id
|
||||||
|
} else if (typeof update.billing_address !== "undefined") {
|
||||||
|
address = update.billing_address
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("discounts" in update) {
|
if (typeof address !== "undefined") {
|
||||||
|
await this.updateBillingAddress_(cart, address, addrRepo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof update.discounts !== "undefined") {
|
||||||
const previousDiscounts = cart.discounts
|
const previousDiscounts = cart.discounts
|
||||||
cart.discounts = []
|
cart.discounts = []
|
||||||
|
|
||||||
@@ -670,7 +808,7 @@ class CartService extends BaseService {
|
|||||||
if ("gift_cards" in update) {
|
if ("gift_cards" in update) {
|
||||||
cart.gift_cards = []
|
cart.gift_cards = []
|
||||||
|
|
||||||
for (const { code } of update.gift_cards) {
|
for (const { code } of update.gift_cards!) {
|
||||||
await this.applyGiftCard_(cart, code)
|
await this.applyGiftCard_(cart, code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -688,11 +826,11 @@ class CartService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ("completed_at" in update) {
|
if ("completed_at" in update) {
|
||||||
cart.completed_at = update.completed_at
|
cart.completed_at = update.completed_at!
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("payment_authorized_at" in update) {
|
if ("payment_authorized_at" in update) {
|
||||||
cart.payment_authorized_at = update.payment_authorized_at
|
cart.payment_authorized_at = update.payment_authorized_at!
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await cartRepo.save(cart)
|
const result = await cartRepo.save(cart)
|
||||||
@@ -717,7 +855,7 @@ class CartService extends BaseService {
|
|||||||
* @param {string} customerId - the customer to add to cart
|
* @param {string} customerId - the customer to add to cart
|
||||||
* @return {Promise} the result of the update operation
|
* @return {Promise} the result of the update operation
|
||||||
*/
|
*/
|
||||||
async updateCustomerId_(cart, customerId) {
|
async updateCustomerId_(cart: Cart, customerId: string): Promise<void> {
|
||||||
const customer = await this.customerService_
|
const customer = await this.customerService_
|
||||||
.withTransaction(this.transactionManager_)
|
.withTransaction(this.transactionManager_)
|
||||||
.retrieve(customerId)
|
.retrieve(customerId)
|
||||||
@@ -732,7 +870,7 @@ class CartService extends BaseService {
|
|||||||
* @param {string} email - the email to use
|
* @param {string} email - the email to use
|
||||||
* @return {Promise} the resultign customer object
|
* @return {Promise} the resultign customer object
|
||||||
*/
|
*/
|
||||||
async createOrFetchUserFromEmail_(email) {
|
async createOrFetchUserFromEmail_(email: string): Promise<Customer> {
|
||||||
const schema = Validator.string().email().required()
|
const schema = Validator.string().email().required()
|
||||||
const { value, error } = schema.validate(email.toLowerCase())
|
const { value, error } = schema.validate(email.toLowerCase())
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -765,17 +903,24 @@ class CartService extends BaseService {
|
|||||||
* updates
|
* updates
|
||||||
* @return {Promise} the result of the update operation
|
* @return {Promise} the result of the update operation
|
||||||
*/
|
*/
|
||||||
async updateBillingAddress_(cart, addressOrId, addrRepo) {
|
async updateBillingAddress_(
|
||||||
|
cart: Cart,
|
||||||
|
addressOrId: Partial<Address> | string,
|
||||||
|
addrRepo: AddressRepository
|
||||||
|
): Promise<void> {
|
||||||
|
let address: Address
|
||||||
if (typeof addressOrId === `string`) {
|
if (typeof addressOrId === `string`) {
|
||||||
addressOrId = await addrRepo.findOne({
|
address = (await addrRepo.findOne({
|
||||||
where: { id: addressOrId },
|
where: { id: addressOrId },
|
||||||
})
|
})) as Address
|
||||||
|
} else {
|
||||||
|
address = addressOrId as Address
|
||||||
}
|
}
|
||||||
|
|
||||||
addressOrId.country_code = addressOrId.country_code.toLowerCase()
|
address.country_code = address.country_code?.toLowerCase() ?? null
|
||||||
|
|
||||||
if (addressOrId.id) {
|
if (address.id) {
|
||||||
const updated = await addrRepo.save(addressOrId)
|
const updated = await addrRepo.save(address)
|
||||||
cart.billing_address = updated
|
cart.billing_address = updated
|
||||||
} else {
|
} else {
|
||||||
if (cart.billing_address_id) {
|
if (cart.billing_address_id) {
|
||||||
@@ -783,10 +928,10 @@ class CartService extends BaseService {
|
|||||||
where: { id: cart.billing_address_id },
|
where: { id: cart.billing_address_id },
|
||||||
})
|
})
|
||||||
|
|
||||||
await addrRepo.save({ ...addr, ...addressOrId })
|
await addrRepo.save({ ...addr, ...address })
|
||||||
} else {
|
} else {
|
||||||
const created = addrRepo.create({
|
const created = addrRepo.create({
|
||||||
...addressOrId,
|
...address,
|
||||||
})
|
})
|
||||||
|
|
||||||
cart.billing_address = created
|
cart.billing_address = created
|
||||||
@@ -803,25 +948,31 @@ class CartService extends BaseService {
|
|||||||
* updates
|
* updates
|
||||||
* @return {Promise} the result of the update operation
|
* @return {Promise} the result of the update operation
|
||||||
*/
|
*/
|
||||||
async updateShippingAddress_(cart, addressOrId, addrRepo) {
|
async updateShippingAddress_(
|
||||||
|
cart: Cart,
|
||||||
|
addressOrId: Partial<Address> | string,
|
||||||
|
addrRepo: AddressRepository
|
||||||
|
): Promise<void> {
|
||||||
|
let address: Address
|
||||||
|
|
||||||
if (addressOrId === null) {
|
if (addressOrId === null) {
|
||||||
cart.shipping_address = null
|
cart.shipping_address = null
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof addressOrId === `string`) {
|
if (typeof addressOrId === `string`) {
|
||||||
addressOrId = await addrRepo.findOne({
|
address = (await addrRepo.findOne({
|
||||||
where: { id: addressOrId },
|
where: { id: addressOrId },
|
||||||
})
|
})) as Address
|
||||||
|
} else {
|
||||||
|
address = addressOrId as Address
|
||||||
}
|
}
|
||||||
|
|
||||||
addressOrId.country_code = addressOrId.country_code?.toLowerCase() ?? null
|
address.country_code = address.country_code?.toLowerCase() ?? null
|
||||||
|
|
||||||
if (
|
if (
|
||||||
addressOrId.country_code &&
|
address.country_code &&
|
||||||
!cart.region.countries.find(
|
!cart.region.countries.find(({ iso_2 }) => address.country_code === iso_2)
|
||||||
({ iso_2 }) => addressOrId.country_code === iso_2
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
@@ -829,8 +980,8 @@ class CartService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addressOrId.id) {
|
if (address.id) {
|
||||||
const updated = await addrRepo.save(addressOrId)
|
const updated = await addrRepo.save(address)
|
||||||
cart.shipping_address = updated
|
cart.shipping_address = updated
|
||||||
} else {
|
} else {
|
||||||
if (cart.shipping_address_id) {
|
if (cart.shipping_address_id) {
|
||||||
@@ -838,10 +989,10 @@ class CartService extends BaseService {
|
|||||||
where: { id: cart.shipping_address_id },
|
where: { id: cart.shipping_address_id },
|
||||||
})
|
})
|
||||||
|
|
||||||
await addrRepo.save({ ...addr, ...addressOrId })
|
await addrRepo.save({ ...addr, ...address })
|
||||||
} else {
|
} else {
|
||||||
const created = addrRepo.create({
|
const created = addrRepo.create({
|
||||||
...addressOrId,
|
...address,
|
||||||
})
|
})
|
||||||
|
|
||||||
cart.shipping_address = created
|
cart.shipping_address = created
|
||||||
@@ -849,7 +1000,7 @@ class CartService extends BaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async applyGiftCard_(cart, code) {
|
async applyGiftCard_(cart: Cart, code: string): Promise<void> {
|
||||||
const giftCard = await this.giftCardService_.retrieveByCode(code)
|
const giftCard = await this.giftCardService_.retrieveByCode(code)
|
||||||
|
|
||||||
if (giftCard.is_disabled) {
|
if (giftCard.is_disabled) {
|
||||||
@@ -883,7 +1034,7 @@ class CartService extends BaseService {
|
|||||||
* @param {string} discountCode - the discount code
|
* @param {string} discountCode - the discount code
|
||||||
* @return {Promise} the result of the update operation
|
* @return {Promise} the result of the update operation
|
||||||
*/
|
*/
|
||||||
async applyDiscount(cart, discountCode) {
|
async applyDiscount(cart: Cart, discountCode: string): Promise<void> {
|
||||||
const discount = await this.discountService_.retrieveByCode(discountCode, [
|
const discount = await this.discountService_.retrieveByCode(discountCode, [
|
||||||
"rule",
|
"rule",
|
||||||
"rule.valid_for",
|
"rule.valid_for",
|
||||||
@@ -982,8 +1133,8 @@ class CartService extends BaseService {
|
|||||||
* @param {string} discountCode - the discount code to remove
|
* @param {string} discountCode - the discount code to remove
|
||||||
* @return {Promise<Cart>} the resulting cart
|
* @return {Promise<Cart>} the resulting cart
|
||||||
*/
|
*/
|
||||||
async removeDiscount(cartId, discountCode) {
|
async removeDiscount(cartId: string, discountCode: string): Promise<Cart> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
relations: [
|
relations: [
|
||||||
"discounts",
|
"discounts",
|
||||||
@@ -1030,8 +1181,8 @@ class CartService extends BaseService {
|
|||||||
* @param {string} cartId - the id of the cart to update the payment session for
|
* @param {string} cartId - the id of the cart to update the payment session for
|
||||||
* @param {object} update - the data to update the payment session with
|
* @param {object} update - the data to update the payment session with
|
||||||
*/
|
*/
|
||||||
async updatePaymentSession(cartId, update) {
|
async updatePaymentSession(cartId: string, update: object): Promise<Cart> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
relations: ["payment_sessions"],
|
relations: ["payment_sessions"],
|
||||||
})
|
})
|
||||||
@@ -1064,8 +1215,8 @@ class CartService extends BaseService {
|
|||||||
* this could be IP address or similar for fraud handling.
|
* this could be IP address or similar for fraud handling.
|
||||||
* @return {Promise<Cart>} the resulting cart
|
* @return {Promise<Cart>} the resulting cart
|
||||||
*/
|
*/
|
||||||
async authorizePayment(cartId, context = {}) {
|
async authorizePayment(cartId: string, context: object = {}): Promise<Cart> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cartRepository = manager.getCustomRepository(this.cartRepository_)
|
const cartRepository = manager.getCustomRepository(this.cartRepository_)
|
||||||
|
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
@@ -1073,6 +1224,13 @@ class CartService extends BaseService {
|
|||||||
relations: ["region", "payment_sessions"],
|
relations: ["region", "payment_sessions"],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (typeof cart.total === "undefined") {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.UNEXPECTED_STATE,
|
||||||
|
"cart.total should be defined"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// If cart total is 0, we don't perform anything payment related
|
// If cart total is 0, we don't perform anything payment related
|
||||||
if (cart.total <= 0) {
|
if (cart.total <= 0) {
|
||||||
cart.payment_authorized_at = new Date()
|
cart.payment_authorized_at = new Date()
|
||||||
@@ -1111,8 +1269,8 @@ class CartService extends BaseService {
|
|||||||
* @param {string} providerId - the id of the provider to be set to the cart
|
* @param {string} providerId - the id of the provider to be set to the cart
|
||||||
* @return {Promise} result of update operation
|
* @return {Promise} result of update operation
|
||||||
*/
|
*/
|
||||||
async setPaymentSession(cartId, providerId) {
|
async setPaymentSession(cartId: string, providerId: string): Promise<Cart> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const psRepo = manager.getCustomRepository(this.paymentSessionRepository_)
|
const psRepo = manager.getCustomRepository(this.paymentSessionRepository_)
|
||||||
|
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
@@ -1141,8 +1299,8 @@ class CartService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
cart.payment_sessions.map((ps) => {
|
cart.payment_sessions.map(async (ps) => {
|
||||||
return psRepo.save({ ...ps, is_selected: null })
|
return await psRepo.save({ ...ps, is_selected: null })
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1150,6 +1308,13 @@ class CartService extends BaseService {
|
|||||||
(ps) => ps.provider_id === providerId
|
(ps) => ps.provider_id === providerId
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (!sess) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.UNEXPECTED_STATE,
|
||||||
|
"Could not find payment session"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
sess.is_selected = true
|
sess.is_selected = true
|
||||||
|
|
||||||
await psRepo.save(sess)
|
await psRepo.save(sess)
|
||||||
@@ -1173,12 +1338,13 @@ class CartService extends BaseService {
|
|||||||
* session for
|
* session for
|
||||||
* @return {Promise} the result of the update operation.
|
* @return {Promise} the result of the update operation.
|
||||||
*/
|
*/
|
||||||
async setPaymentSessions(cartOrCartId) {
|
async setPaymentSessions(cartOrCartId: Cart | string): Promise<Cart> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const psRepo = manager.getCustomRepository(this.paymentSessionRepository_)
|
const psRepo = manager.getCustomRepository(this.paymentSessionRepository_)
|
||||||
|
|
||||||
const cartId =
|
const cartId =
|
||||||
typeof cartOrCartId === `string` ? cartOrCartId : cartOrCartId.id
|
typeof cartOrCartId === `string` ? cartOrCartId : cartOrCartId.id
|
||||||
|
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
select: [
|
select: [
|
||||||
"gift_card_total",
|
"gift_card_total",
|
||||||
@@ -1205,8 +1371,15 @@ class CartService extends BaseService {
|
|||||||
|
|
||||||
const region = cart.region
|
const region = cart.region
|
||||||
|
|
||||||
|
if (typeof cart.total === "undefined") {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.UNEXPECTED_STATE,
|
||||||
|
"cart.total should be defined"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// If there are existing payment sessions ensure that these are up to date
|
// If there are existing payment sessions ensure that these are up to date
|
||||||
const seen = []
|
const seen: string[] = []
|
||||||
if (cart.payment_sessions && cart.payment_sessions.length) {
|
if (cart.payment_sessions && cart.payment_sessions.length) {
|
||||||
for (const session of cart.payment_sessions) {
|
for (const session of cart.payment_sessions) {
|
||||||
if (
|
if (
|
||||||
@@ -1258,8 +1431,11 @@ class CartService extends BaseService {
|
|||||||
* should be removed.
|
* should be removed.
|
||||||
* @return {Promise<Cart>} the resulting cart.
|
* @return {Promise<Cart>} the resulting cart.
|
||||||
*/
|
*/
|
||||||
async deletePaymentSession(cartId, providerId) {
|
async deletePaymentSession(
|
||||||
return this.atomicPhase_(async (manager) => {
|
cartId: string,
|
||||||
|
providerId: string
|
||||||
|
): Promise<Cart> {
|
||||||
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
relations: ["payment_sessions"],
|
relations: ["payment_sessions"],
|
||||||
})
|
})
|
||||||
@@ -1299,8 +1475,11 @@ class CartService extends BaseService {
|
|||||||
* should be removed.
|
* should be removed.
|
||||||
* @return {Promise<Cart>} the resulting cart.
|
* @return {Promise<Cart>} the resulting cart.
|
||||||
*/
|
*/
|
||||||
async refreshPaymentSession(cartId, providerId) {
|
async refreshPaymentSession(
|
||||||
return this.atomicPhase_(async (manager) => {
|
cartId: string,
|
||||||
|
providerId: string
|
||||||
|
): Promise<Cart> {
|
||||||
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
relations: ["payment_sessions"],
|
relations: ["payment_sessions"],
|
||||||
})
|
})
|
||||||
@@ -1338,8 +1517,12 @@ class CartService extends BaseService {
|
|||||||
* @param {Object} data - the fulmillment data for the method
|
* @param {Object} data - the fulmillment data for the method
|
||||||
* @return {Promise} the result of the update operation
|
* @return {Promise} the result of the update operation
|
||||||
*/
|
*/
|
||||||
async addShippingMethod(cartId, optionId, data) {
|
async addShippingMethod(
|
||||||
return this.atomicPhase_(async (manager) => {
|
cartId: string,
|
||||||
|
optionId: string,
|
||||||
|
data: object = {}
|
||||||
|
): Promise<Cart> {
|
||||||
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
select: ["subtotal"],
|
select: ["subtotal"],
|
||||||
relations: [
|
relations: [
|
||||||
@@ -1431,7 +1614,10 @@ class CartService extends BaseService {
|
|||||||
* @param {string} optionId - id of the normal or custom shipping option to find in the cartCustomShippingOptions
|
* @param {string} optionId - id of the normal or custom shipping option to find in the cartCustomShippingOptions
|
||||||
* @return {CustomShippingOption | undefined}
|
* @return {CustomShippingOption | undefined}
|
||||||
*/
|
*/
|
||||||
findCustomShippingOption(cartCustomShippingOptions, optionId) {
|
findCustomShippingOption(
|
||||||
|
cartCustomShippingOptions: CustomShippingOption[],
|
||||||
|
optionId: string
|
||||||
|
): CustomShippingOption | undefined {
|
||||||
const customOption = cartCustomShippingOptions?.find(
|
const customOption = cartCustomShippingOptions?.find(
|
||||||
(cso) => cso.shipping_option_id === optionId
|
(cso) => cso.shipping_option_id === optionId
|
||||||
)
|
)
|
||||||
@@ -1454,7 +1640,11 @@ class CartService extends BaseService {
|
|||||||
* @param {string} countryCode - the country code to set the country to
|
* @param {string} countryCode - the country code to set the country to
|
||||||
* @return {Promise} the result of the update operation
|
* @return {Promise} the result of the update operation
|
||||||
*/
|
*/
|
||||||
async setRegion_(cart, regionId, countryCode) {
|
async setRegion_(
|
||||||
|
cart: Cart,
|
||||||
|
regionId: string,
|
||||||
|
countryCode: string | null
|
||||||
|
): Promise<void> {
|
||||||
if (cart.completed_at || cart.payment_authorized_at) {
|
if (cart.completed_at || cart.payment_authorized_at) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.NOT_ALLOWED,
|
MedusaError.Types.NOT_ALLOWED,
|
||||||
@@ -1506,18 +1696,18 @@ class CartService extends BaseService {
|
|||||||
* First check if there is an existing shipping address on the cart if so
|
* First check if there is an existing shipping address on the cart if so
|
||||||
* fetch the entire thing so we can modify the shipping country
|
* fetch the entire thing so we can modify the shipping country
|
||||||
*/
|
*/
|
||||||
let shippingAddress = {}
|
let shippingAddress: Partial<Address> = {}
|
||||||
if (cart.shipping_address_id) {
|
if (cart.shipping_address_id) {
|
||||||
shippingAddress = await addrRepo.findOne({
|
shippingAddress = (await addrRepo.findOne({
|
||||||
where: { id: cart.shipping_address_id },
|
where: { id: cart.shipping_address_id },
|
||||||
})
|
})) as Address
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the client has specified which country code we are updating to check
|
* If the client has specified which country code we are updating to check
|
||||||
* that that country is in fact in the country and perform the update.
|
* that that country is in fact in the country and perform the update.
|
||||||
*/
|
*/
|
||||||
if (countryCode !== undefined) {
|
if (countryCode !== null) {
|
||||||
if (
|
if (
|
||||||
!region.countries.find(
|
!region.countries.find(
|
||||||
({ iso_2 }) => iso_2 === countryCode.toLowerCase()
|
({ iso_2 }) => iso_2 === countryCode.toLowerCase()
|
||||||
@@ -1580,9 +1770,10 @@ class CartService extends BaseService {
|
|||||||
if (d.regions.find(({ id }) => id === regionId)) {
|
if (d.regions.find(({ id }) => id === regionId)) {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
})
|
})
|
||||||
|
|
||||||
cart.discounts = newDiscounts.filter((d) => !!d)
|
cart.discounts = newDiscounts.filter(Boolean) as Discount[]
|
||||||
}
|
}
|
||||||
|
|
||||||
cart.gift_cards = []
|
cart.gift_cards = []
|
||||||
@@ -1603,11 +1794,11 @@ class CartService extends BaseService {
|
|||||||
/**
|
/**
|
||||||
* Deletes a cart from the database. Completed carts cannot be deleted.
|
* Deletes a cart from the database. Completed carts cannot be deleted.
|
||||||
* @param {string} cartId - the id of the cart to delete
|
* @param {string} cartId - the id of the cart to delete
|
||||||
* @return {Promise<Cart?>} the deleted cart or undefined if the cart was
|
* @return {Promise<string>} the deleted cart or undefined if the cart was
|
||||||
* not found.
|
* not found.
|
||||||
*/
|
*/
|
||||||
async delete(cartId) {
|
async delete(cartId: string): Promise<string> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return await this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cart = await this.retrieve(cartId, {
|
const cart = await this.retrieve(cartId, {
|
||||||
relations: [
|
relations: [
|
||||||
"items",
|
"items",
|
||||||
@@ -1633,7 +1824,7 @@ class CartService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
||||||
return cartRepo.remove(cartId)
|
return cartRepo.remove(cart)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1646,8 +1837,12 @@ class CartService extends BaseService {
|
|||||||
* @param {string} value - value for metadata field.
|
* @param {string} value - value for metadata field.
|
||||||
* @return {Promise} resolves to the updated result.
|
* @return {Promise} resolves to the updated result.
|
||||||
*/
|
*/
|
||||||
async setMetadata(cartId, key, value) {
|
async setMetadata(
|
||||||
return this.atomicPhase_(async (manager) => {
|
cartId: string,
|
||||||
|
key: string,
|
||||||
|
value: string | number
|
||||||
|
): Promise<Cart> {
|
||||||
|
return await this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
||||||
|
|
||||||
const validatedId = this.validateId_(cartId)
|
const validatedId = this.validateId_(cartId)
|
||||||
@@ -1658,7 +1853,7 @@ class CartService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const cart = await cartRepo.findOne(validatedId)
|
const cart = (await cartRepo.findOne(validatedId)) as Cart
|
||||||
|
|
||||||
const existing = cart.metadata || {}
|
const existing = cart.metadata || {}
|
||||||
cart.metadata = {
|
cart.metadata = {
|
||||||
@@ -1680,8 +1875,8 @@ class CartService extends BaseService {
|
|||||||
* @param {string} key - key for metadata field
|
* @param {string} key - key for metadata field
|
||||||
* @return {Promise} resolves to the updated result.
|
* @return {Promise} resolves to the updated result.
|
||||||
*/
|
*/
|
||||||
async deleteMetadata(cartId, key) {
|
async deleteMetadata(cartId: string, key: string): Promise<Cart> {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
||||||
const validatedId = this.validateId_(cartId)
|
const validatedId = this.validateId_(cartId)
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ class InventoryService extends BaseService {
|
|||||||
* allows backorders or if the inventory quantity is greater than `quantity`.
|
* allows backorders or if the inventory quantity is greater than `quantity`.
|
||||||
* @param {string} variantId - the id of the variant to check
|
* @param {string} variantId - the id of the variant to check
|
||||||
* @param {number} quantity - the number of units to check availability for
|
* @param {number} quantity - the number of units to check availability for
|
||||||
* @return {boolean} true if the inventory covers the quantity
|
* @return {Promise<boolean>} true if the inventory covers the quantity
|
||||||
*/
|
*/
|
||||||
async confirmInventory(variantId, quantity) {
|
async confirmInventory(variantId, quantity) {
|
||||||
// if variantId is undefined then confirm inventory as it
|
// if variantId is undefined then confirm inventory as it
|
||||||
|
|||||||
@@ -201,7 +201,7 @@ class ShippingOptionService extends BaseService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a given shipping method
|
* Removes a given shipping method
|
||||||
* @param {string} sm - the shipping method to remove
|
* @param {ShippingMethod} sm - the shipping method to remove
|
||||||
*/
|
*/
|
||||||
async deleteShippingMethod(sm) {
|
async deleteShippingMethod(sm) {
|
||||||
return this.atomicPhase_(async (manager) => {
|
return this.atomicPhase_(async (manager) => {
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { ValidateNested } from "class-validator"
|
||||||
|
import { IsType } from "../utils/validators/is-type"
|
||||||
|
import { CartType } from "../models/cart"
|
||||||
|
import {
|
||||||
|
AddressPayload,
|
||||||
|
DateComparisonOperator,
|
||||||
|
StringComparisonOperator,
|
||||||
|
} from "./common"
|
||||||
|
|
||||||
|
export class FilterableCartProps {
|
||||||
|
@ValidateNested()
|
||||||
|
@IsType([String, [String], StringComparisonOperator])
|
||||||
|
id?: string | string[] | StringComparisonOperator
|
||||||
|
|
||||||
|
@IsType([DateComparisonOperator])
|
||||||
|
created_at?: DateComparisonOperator
|
||||||
|
|
||||||
|
@IsType([DateComparisonOperator])
|
||||||
|
updated_at?: DateComparisonOperator
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Probably worth moving to `./line-item` instead
|
||||||
|
export type LineItemUpdate = {
|
||||||
|
title?: string
|
||||||
|
unit_price?: number
|
||||||
|
quantity?: number
|
||||||
|
metadata?: object
|
||||||
|
region_id?: string
|
||||||
|
variant_id?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
class GiftCard {
|
||||||
|
code: string
|
||||||
|
}
|
||||||
|
|
||||||
|
class Discount {
|
||||||
|
code: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CartCreateProps = {
|
||||||
|
region_id: string
|
||||||
|
email?: string
|
||||||
|
billing_address_id?: string
|
||||||
|
billing_address?: Partial<AddressPayload>
|
||||||
|
shipping_address_id?: string
|
||||||
|
shipping_address?: Partial<AddressPayload>
|
||||||
|
gift_cards?: GiftCard[]
|
||||||
|
discounts?: Discount[]
|
||||||
|
customer_id?: string
|
||||||
|
type?: CartType
|
||||||
|
context?: object
|
||||||
|
metadata?: object
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CartUpdateProps = {
|
||||||
|
region_id?: string
|
||||||
|
country_code?: string
|
||||||
|
email?: string
|
||||||
|
shipping_address_id?: string
|
||||||
|
billing_address_id?: string
|
||||||
|
billing_address?: AddressPayload
|
||||||
|
shipping_address?: AddressPayload
|
||||||
|
completed_at?: Date
|
||||||
|
payment_authorized_at?: Date
|
||||||
|
gift_cards?: GiftCard[]
|
||||||
|
discounts?: Discount[]
|
||||||
|
customer_id?: string
|
||||||
|
context?: object
|
||||||
|
metadata?: object
|
||||||
|
}
|
||||||
@@ -8,6 +8,16 @@ export type PartialPick<T, K extends keyof T> = {
|
|||||||
[P in K]?: T[P]
|
[P in K]?: T[P]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TotalField =
|
||||||
|
| "shipping_total"
|
||||||
|
| "discount_total"
|
||||||
|
| "tax_total"
|
||||||
|
| "refunded_total"
|
||||||
|
| "total"
|
||||||
|
| "subtotal"
|
||||||
|
| "refundable_amount"
|
||||||
|
| "gift_card_total"
|
||||||
|
|
||||||
export interface FindConfig<Entity> {
|
export interface FindConfig<Entity> {
|
||||||
select?: (keyof Entity)[]
|
select?: (keyof Entity)[]
|
||||||
skip?: number
|
skip?: number
|
||||||
|
|||||||
Reference in new issue
Block a user