fix: shipping option updates (#426)

* fix to remove req

* tested fix
This commit is contained in:
Kasper Fabricius Kristensen
2021-10-01 08:18:56 +02:00
committed by GitHub
parent cd4afd1576
commit 22f3f2af93
4 changed files with 66 additions and 41 deletions

View File

@@ -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"`
)
}
}

View File

@@ -16,7 +16,7 @@ import {
JoinTable,
} from "typeorm"
import { ulid } from "ulid"
import { DbAwareColumn } from "../utils/db-aware-column"
import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column"
import { ShippingOption } from "./shipping-option"
@@ -44,6 +44,9 @@ export class ShippingOptionRequirement {
@Column({ type: "int" })
amount: number
@DeleteDateColumn({ type: resolveDbType("timestamptz") })
deleted_at: Date
@BeforeInsert()
private beforeInsert() {
if (this.id) return

View File

@@ -296,24 +296,19 @@ describe("ShippingOptionService", () => {
})
describe("removeRequirement", () => {
const shippingOptionRepository = MockRepository({
findOne: q => {
switch (q.where.id) {
default:
return Promise.resolve({
requirements: [
{
id: IdMap.getId("requirement_id"),
},
],
})
}
const shippingOptionRequirementRepository = MockRepository({
softRemove: q => {
return Promise.resolve()
},
findOne: i =>
i.where.id === IdMap.getId("requirement_id")
? { id: IdMap.getId("requirement_id") }
: null,
})
const optionService = new ShippingOptionService({
manager: MockManager,
shippingOptionRepository,
shippingOptionRequirementRepository,
})
beforeEach(() => {
@@ -321,22 +316,19 @@ describe("ShippingOptionService", () => {
})
it("remove requirement successfully", async () => {
await optionService.removeRequirement(
IdMap.getId("validId"),
IdMap.getId("requirement_id")
)
await optionService.removeRequirement(IdMap.getId("requirement_id"))
expect(shippingOptionRepository.save).toBeCalledTimes(1)
expect(shippingOptionRepository.save).toBeCalledWith({ requirements: [] })
expect(shippingOptionRequirementRepository.findOne).toBeCalledTimes(1)
expect(shippingOptionRequirementRepository.findOne).toBeCalledWith({
where: { id: IdMap.getId("requirement_id") },
})
expect(shippingOptionRequirementRepository.softRemove).toBeCalledTimes(1)
})
it("is idempotent", async () => {
await optionService.removeRequirement(IdMap.getId("validId"), "something")
expect(shippingOptionRepository.save).toBeCalledTimes(1)
expect(shippingOptionRepository.save).toBeCalledWith({
requirements: [{ id: IdMap.getId("requirement_id") }],
})
expect(shippingOptionRequirementRepository.softRemove).toBeCalledTimes(1)
})
})

View File

@@ -450,7 +450,9 @@ class ShippingOptionService extends BaseService {
*/
async update(optionId, update) {
return this.atomicPhase_(async manager => {
const option = await this.retrieve(optionId)
const option = await this.retrieve(optionId, {
relations: ["requirements"],
})
if ("metadata" in update) {
option.metadata = await this.setMetadata_(option, update.metadata)
@@ -498,6 +500,20 @@ class ShippingOptionService extends BaseService {
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) {
@@ -585,28 +601,24 @@ class ShippingOptionService extends BaseService {
/**
* 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
* @return {Promise} the result of update
*/
async removeRequirement(optionId, requirementId) {
async removeRequirement(requirementId) {
return this.atomicPhase_(async manager => {
const option = await this.retrieve(optionId, {
relations: "requirements",
})
const newReqs = option.requirements.map(r => {
if (r.id === requirementId) {
return null
} else {
return r
}
})
try {
const reqRepo = manager.getCustomRepository(this.requirementRepository_)
const requirement = await reqRepo.findOne({
where: { id: requirementId },
})
option.requirements = newReqs.filter(Boolean)
const result = await reqRepo.softRemove(requirement)
const optionRepo = manager.getCustomRepository(this.optionRepository_)
const result = await optionRepo.save(option)
return result
return result
} catch (error) {
// Delete is idempotent, but we return a promise to allow then-chaining
return Promise.resolve()
}
})
}