Files
medusa-store/packages/medusa/src/models/order-edit.ts
Patrick 507ad00bec feat(oas) - accurate model OAS representation - F to O (#3210)
### Scope

Models F to O

### What

Refactor OAS for models to accurately represent their shape in API responses.

### Why

About 33% of model fields are not accurately represented in the OAS. Most of the issues are:
- fields that can not be omitted in the response are not declared as `required`
- fields that could return `null` as their value are not declared as `nullable: true`

When using a code generator, these OAS issues would lead to inaccurate response shapes in the generated client.

### How

#### nullable
Fields meeting at least one of the following condition will be represented as `nullable: true` in OAS:
* The field is decorated with `@Column({ nullable: true })`
* The field is decorated with `@OneToOne`, `@ManyToOne`
* The field is decorated with `@DeleteDateColumn`

#### optional
Fields meeting at least one of the following conditions will never be listed as `required` in OAS and will be considered optional and could be omitted in the response:
* The field is decorated with `@OneToOne`, `@ManyToOne`, `@OneToMany`, `@ManyToMany`
* The field is decorated with `@FeatureFlagColumn`
* The field is decorated with `@Column({select: false})`
* The field is representing dynamic values not persisted in the database

Fields not meeting any of the conditions above will be declared as `required` and are expected to be present in the response.

### Test
* Ran OAS validator.
* Ran docs build script.

Expect OAS changes to be reflected in the API documentation.
2023-02-09 15:03:11 +00:00

276 lines
7.2 KiB
TypeScript

import {
AfterLoad,
BeforeInsert,
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
OneToMany,
OneToOne,
} from "typeorm"
import { BaseEntity } from "../interfaces"
import { generateEntityId } from "../utils"
import { resolveDbType } from "../utils/db-aware-column"
import { LineItem, Order, OrderItemChange, PaymentCollection } from "."
export enum OrderEditStatus {
CONFIRMED = "confirmed",
DECLINED = "declined",
REQUESTED = "requested",
CREATED = "created",
CANCELED = "canceled",
}
@Entity()
export class OrderEdit extends BaseEntity {
@Index()
@Column()
order_id: string
@ManyToOne(() => Order, (o) => o.edits)
@JoinColumn({ name: "order_id" })
order: Order
@OneToMany(() => OrderItemChange, (oic) => oic.order_edit, {
cascade: true,
})
changes: OrderItemChange[]
@Column({ nullable: true })
internal_note?: string
@Column()
created_by: string // customer, user, third party, etc.
@Column({ nullable: true })
requested_by?: string // customer or user ID
@Column({ type: resolveDbType("timestamptz"), nullable: true })
requested_at?: Date
@Column({ nullable: true })
confirmed_by?: string // customer or user ID
@Column({ type: resolveDbType("timestamptz"), nullable: true })
confirmed_at?: Date
@Column({ nullable: true })
declined_by?: string // customer or user ID
@Column({ nullable: true })
declined_reason?: string
@Column({ type: resolveDbType("timestamptz"), nullable: true })
declined_at?: Date
@Column({ nullable: true })
canceled_by?: string
@Column({ type: resolveDbType("timestamptz"), nullable: true })
canceled_at?: Date
@OneToMany(() => LineItem, (lineItem) => lineItem.order_edit)
items: LineItem[]
@Index()
@Column({ nullable: true })
payment_collection_id: string
@OneToOne(() => PaymentCollection)
@JoinColumn({ name: "payment_collection_id" })
payment_collection: PaymentCollection
// Computed
shipping_total: number
discount_total: number
tax_total: number | null
total: number
subtotal: number
gift_card_total: number
gift_card_tax_total: number
difference_due: number
status: OrderEditStatus
@BeforeInsert()
private beforeInsert(): void {
this.id = generateEntityId(this.id, "oe")
}
@AfterLoad()
loadStatus(): void {
if (this.requested_at) {
this.status = OrderEditStatus.REQUESTED
}
if (this.declined_at) {
this.status = OrderEditStatus.DECLINED
}
if (this.confirmed_at) {
this.status = OrderEditStatus.CONFIRMED
}
if (this.canceled_at) {
this.status = OrderEditStatus.CANCELED
}
this.status = this.status ?? OrderEditStatus.CREATED
}
}
/**
* @schema OrderEdit
* title: "Order Edit"
* description: "Order edit keeps track of order items changes."
* type: object
* required:
* - canceled_at
* - canceled_by
* - confirmed_by
* - confirmed_at
* - created_at
* - created_by
* - declined_at
* - declined_by
* - declined_reason
* - id
* - internal_note
* - order_id
* - payment_collection_id
* - requested_at
* - requested_by
* - status
* - updated_at
* properties:
* id:
* description: The order edit's ID
* type: string
* example: oe_01G8TJSYT9M6AVS5N4EMNFS1EK
* order_id:
* description: The ID of the order that is edited
* type: string
* example: order_01G2SG30J8C85S4A5CHM2S1NS2
* order:
* description: Available if the relation `order` is expanded.
* nullable: true
* $ref: "#/components/schemas/Order"
* changes:
* description: Available if the relation `changes` is expanded.
* type: array
* items:
* $ref: "#/components/schemas/OrderItemChange"
* internal_note:
* description: An optional note with additional details about the order edit.
* nullable: true
* type: string
* example: Included two more items B to the order.
* created_by:
* description: The unique identifier of the user or customer who created the order edit.
* type: string
* requested_by:
* description: The unique identifier of the user or customer who requested the order edit.
* nullable: true
* type: string
* requested_at:
* description: The date with timezone at which the edit was requested.
* nullable: true
* type: string
* format: date-time
* confirmed_by:
* description: The unique identifier of the user or customer who confirmed the order edit.
* nullable: true
* type: string
* confirmed_at:
* description: The date with timezone at which the edit was confirmed.
* nullable: true
* type: string
* format: date-time
* declined_by:
* description: The unique identifier of the user or customer who declined the order edit.
* nullable: true
* type: string
* declined_at:
* description: The date with timezone at which the edit was declined.
* nullable: true
* type: string
* format: date-time
* declined_reason:
* description: An optional note why the order edit is declined.
* nullable: true
* type: string
* canceled_by:
* description: The unique identifier of the user or customer who cancelled the order edit.
* nullable: true
* type: string
* canceled_at:
* description: The date with timezone at which the edit was cancelled.
* nullable: true
* type: string
* format: date-time
* subtotal:
* description: The total of subtotal
* type: integer
* example: 8000
* discount_total:
* description: The total of discount
* type: integer
* example: 800
* shipping_total:
* description: The total of the shipping amount
* type: integer
* example: 800
* gift_card_total:
* description: The total of the gift card amount
* type: integer
* example: 800
* gift_card_tax_total:
* description: The total of the gift card tax amount
* type: integer
* example: 800
* tax_total:
* description: The total of tax
* type: integer
* example: 0
* total:
* description: The total amount of the edited order.
* type: integer
* example: 8200
* difference_due:
* description: The difference between the total amount of the order and total amount of edited order.
* type: integer
* example: 8200
* status:
* description: The status of the order edit.
* type: string
* enum:
* - confirmed
* - declined
* - requested
* - created
* - canceled
* items:
* description: Available if the relation `items` is expanded.
* type: array
* items:
* $ref: "#/components/schemas/LineItem"
* payment_collection_id:
* description: The ID of the payment collection
* nullable: true
* type: string
* example: paycol_01G8TJSYT9M6AVS5N4EMNFS1EK
* payment_collection:
* description: Available if the relation `payment_collection` is expanded.
* nullable: true
* $ref: "#/components/schemas/PaymentCollection"
* created_at:
* description: The date with timezone at which the resource was created.
* type: string
* format: date-time
* updated_at:
* description: The date with timezone at which the resource was updated.
* type: string
* format: date-time
*/