+18
@@ -0,0 +1,18 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm"
|
||||||
|
|
||||||
|
export class deleteDateOnShippingOptionRequirements1632828114899
|
||||||
|
implements MigrationInterface {
|
||||||
|
name = "deleteDateOnShippingOptionRequirements1632828114899"
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "shipping_option_requirement" ADD "deleted_at" TIMESTAMP WITH TIME ZONE`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "shipping_option_requirement" DROP COLUMN "deleted_at"`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,7 +16,7 @@ import {
|
|||||||
JoinTable,
|
JoinTable,
|
||||||
} from "typeorm"
|
} from "typeorm"
|
||||||
import { ulid } from "ulid"
|
import { ulid } from "ulid"
|
||||||
import { DbAwareColumn } from "../utils/db-aware-column"
|
import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column"
|
||||||
|
|
||||||
import { ShippingOption } from "./shipping-option"
|
import { ShippingOption } from "./shipping-option"
|
||||||
|
|
||||||
@@ -44,6 +44,9 @@ export class ShippingOptionRequirement {
|
|||||||
@Column({ type: "int" })
|
@Column({ type: "int" })
|
||||||
amount: number
|
amount: number
|
||||||
|
|
||||||
|
@DeleteDateColumn({ type: resolveDbType("timestamptz") })
|
||||||
|
deleted_at: Date
|
||||||
|
|
||||||
@BeforeInsert()
|
@BeforeInsert()
|
||||||
private beforeInsert() {
|
private beforeInsert() {
|
||||||
if (this.id) return
|
if (this.id) return
|
||||||
|
|||||||
@@ -296,24 +296,19 @@ describe("ShippingOptionService", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("removeRequirement", () => {
|
describe("removeRequirement", () => {
|
||||||
const shippingOptionRepository = MockRepository({
|
const shippingOptionRequirementRepository = MockRepository({
|
||||||
findOne: q => {
|
softRemove: q => {
|
||||||
switch (q.where.id) {
|
return Promise.resolve()
|
||||||
default:
|
|
||||||
return Promise.resolve({
|
|
||||||
requirements: [
|
|
||||||
{
|
|
||||||
id: IdMap.getId("requirement_id"),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
findOne: i =>
|
||||||
|
i.where.id === IdMap.getId("requirement_id")
|
||||||
|
? { id: IdMap.getId("requirement_id") }
|
||||||
|
: null,
|
||||||
})
|
})
|
||||||
|
|
||||||
const optionService = new ShippingOptionService({
|
const optionService = new ShippingOptionService({
|
||||||
manager: MockManager,
|
manager: MockManager,
|
||||||
shippingOptionRepository,
|
shippingOptionRequirementRepository,
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -321,22 +316,19 @@ describe("ShippingOptionService", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("remove requirement successfully", async () => {
|
it("remove requirement successfully", async () => {
|
||||||
await optionService.removeRequirement(
|
await optionService.removeRequirement(IdMap.getId("requirement_id"))
|
||||||
IdMap.getId("validId"),
|
|
||||||
IdMap.getId("requirement_id")
|
|
||||||
)
|
|
||||||
|
|
||||||
expect(shippingOptionRepository.save).toBeCalledTimes(1)
|
expect(shippingOptionRequirementRepository.findOne).toBeCalledTimes(1)
|
||||||
expect(shippingOptionRepository.save).toBeCalledWith({ requirements: [] })
|
expect(shippingOptionRequirementRepository.findOne).toBeCalledWith({
|
||||||
|
where: { id: IdMap.getId("requirement_id") },
|
||||||
|
})
|
||||||
|
expect(shippingOptionRequirementRepository.softRemove).toBeCalledTimes(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("is idempotent", async () => {
|
it("is idempotent", async () => {
|
||||||
await optionService.removeRequirement(IdMap.getId("validId"), "something")
|
await optionService.removeRequirement(IdMap.getId("validId"), "something")
|
||||||
|
|
||||||
expect(shippingOptionRepository.save).toBeCalledTimes(1)
|
expect(shippingOptionRequirementRepository.softRemove).toBeCalledTimes(1)
|
||||||
expect(shippingOptionRepository.save).toBeCalledWith({
|
|
||||||
requirements: [{ id: IdMap.getId("requirement_id") }],
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -450,7 +450,9 @@ class ShippingOptionService extends BaseService {
|
|||||||
*/
|
*/
|
||||||
async update(optionId, update) {
|
async update(optionId, update) {
|
||||||
return this.atomicPhase_(async manager => {
|
return this.atomicPhase_(async manager => {
|
||||||
const option = await this.retrieve(optionId)
|
const option = await this.retrieve(optionId, {
|
||||||
|
relations: ["requirements"],
|
||||||
|
})
|
||||||
|
|
||||||
if ("metadata" in update) {
|
if ("metadata" in update) {
|
||||||
option.metadata = await this.setMetadata_(option, update.metadata)
|
option.metadata = await this.setMetadata_(option, update.metadata)
|
||||||
@@ -498,6 +500,20 @@ class ShippingOptionService extends BaseService {
|
|||||||
|
|
||||||
acc.push(validated)
|
acc.push(validated)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (option.requirements) {
|
||||||
|
const accReqs = acc.map(a => a.id)
|
||||||
|
const toRemove = option.requirements.filter(
|
||||||
|
r => !accReqs.includes(r.id)
|
||||||
|
)
|
||||||
|
await Promise.all(
|
||||||
|
toRemove.map(async req => {
|
||||||
|
await this.removeRequirement(req.id)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
option.requirements = acc
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("price_type" in update) {
|
if ("price_type" in update) {
|
||||||
@@ -585,28 +601,24 @@ class ShippingOptionService extends BaseService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a requirement from a shipping option
|
* Removes a requirement from a shipping option
|
||||||
* @param {string} optionId - the shipping option to remove from
|
|
||||||
* @param {string} requirementId - the id of the requirement to remove
|
* @param {string} requirementId - the id of the requirement to remove
|
||||||
* @return {Promise} the result of update
|
* @return {Promise} the result of update
|
||||||
*/
|
*/
|
||||||
async removeRequirement(optionId, requirementId) {
|
async removeRequirement(requirementId) {
|
||||||
return this.atomicPhase_(async manager => {
|
return this.atomicPhase_(async manager => {
|
||||||
const option = await this.retrieve(optionId, {
|
try {
|
||||||
relations: "requirements",
|
const reqRepo = manager.getCustomRepository(this.requirementRepository_)
|
||||||
})
|
const requirement = await reqRepo.findOne({
|
||||||
const newReqs = option.requirements.map(r => {
|
where: { id: requirementId },
|
||||||
if (r.id === requirementId) {
|
})
|
||||||
return null
|
|
||||||
} else {
|
|
||||||
return r
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
option.requirements = newReqs.filter(Boolean)
|
const result = await reqRepo.softRemove(requirement)
|
||||||
|
|
||||||
const optionRepo = manager.getCustomRepository(this.optionRepository_)
|
return result
|
||||||
const result = await optionRepo.save(option)
|
} catch (error) {
|
||||||
return result
|
// Delete is idempotent, but we return a promise to allow then-chaining
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user