Skip to content

Commit

Permalink
feat(tax): adds udpate tax rate
Browse files Browse the repository at this point in the history
  • Loading branch information
srindom committed Feb 28, 2024
1 parent c836b6c commit ff50917
Show file tree
Hide file tree
Showing 11 changed files with 265 additions and 0 deletions.
96 changes: 96 additions & 0 deletions integration-tests/plugins/__tests__/tax/admin/tax.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,4 +208,100 @@ describe("Taxes - Admin", () => {
])
)
})

it("can create a tax rate and update it", async () => {
const api = useApi() as any
const regionRes = await api.post(
`/admin/tax-regions`,
{
country_code: "us",
default_tax_rate: {
code: "default",
rate: 2,
name: "default rate",
},
},
adminHeaders
)

const usRegionId = regionRes.data.tax_region.id

expect(regionRes.status).toEqual(200)
expect(regionRes.data).toEqual({
tax_region: {
id: expect.any(String),
country_code: "us",
parent_id: null,
province_code: null,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
created_by: "admin_user",
provider_id: null,
metadata: null,
tax_rates: [],
children: [],
},
})

const rateRes = await api.post(
`/admin/tax-rates`,
{
tax_region_id: usRegionId,
code: "RATE2",
name: "another rate",
rate: 10,
rules: [{ reference: "product", reference_id: "prod_1234" }],
},
adminHeaders
)

expect(rateRes.status).toEqual(200)
expect(rateRes.data).toEqual({
tax_rate: {
id: expect.any(String),
code: "RATE2",
rate: 10,
name: "another rate",
is_default: false,
metadata: null,
tax_region_id: usRegionId,
deleted_at: null,
created_by: "admin_user",
rules: [],
is_combinable: false,
},
})

const updateRes = await api.post(
`/admin/tax-rates/${rateRes.data.tax_rate.id}`,
{
code: "updatedcode",
rate: 12,
is_combinable: true,
name: "Another Name",
metadata: { you: "know it" },
},
adminHeaders
)

expect(updateRes.status).toEqual(200)
expect(updateRes.data).toEqual({
tax_rate: {
id: expect.any(String),
code: "updatedcode",
rate: 12,
name: "Another Name",
is_default: false,
metadata: { you: "know it" },
tax_region_id: usRegionId,
deleted_at: null,
created_at: expect.any(String),
updated_at: expect.any(String),
created_by: "admin_user",
tax_region: { id: usRegionId },
is_combinable: true,
},
})
})
})
1 change: 1 addition & 0 deletions packages/core-flows/src/tax/steps/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./create-tax-regions"
export * from "./create-tax-rates"
export * from "./update-tax-rates"
54 changes: 54 additions & 0 deletions packages/core-flows/src/tax/steps/update-tax-rates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import {
FilterableTaxRateProps,
ITaxModuleService,
UpdateTaxRateDTO,
} from "@medusajs/types"
import { getSelectsAndRelationsFromObjectArray } from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"

type UpdateTaxRatesStepInput = {
selector: FilterableTaxRateProps
update: UpdateTaxRateDTO
}

export const updateTaxRatesStepId = "update-tax-rate"
export const updateTaxRatesStep = createStep(
updateTaxRatesStepId,
async (data: UpdateTaxRatesStepInput, { container }) => {
const service = container.resolve<ITaxModuleService>(
ModuleRegistrationName.TAX
)

const { selects, relations } = getSelectsAndRelationsFromObjectArray([
data.update,
])

const prevData = await service.list(data.selector, {
select: selects,
relations,
})

const taxRates = await service.update(data.selector, data.update)

return new StepResponse(taxRates, prevData)
},
async (prevData, { container }) => {
if (!prevData?.length) {
return
}

const service = container.resolve<ITaxModuleService>(
ModuleRegistrationName.TAX
)

await service.upsert(
prevData.map((r) => ({
id: r.id,
name: r.name,
rate: r.rate,
metadata: r.metadata,
}))
)
}
)
1 change: 1 addition & 0 deletions packages/core-flows/src/tax/workflows/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from "./create-tax-regions"
export * from "./create-tax-rates"
export * from "./update-tax-rates"
22 changes: 22 additions & 0 deletions packages/core-flows/src/tax/workflows/update-tax-rates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import {
FilterableTaxRateProps,
TaxRateDTO,
UpdateTaxRateDTO,
} from "@medusajs/types"
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { updateTaxRatesStep } from "../steps"

type UpdateTaxRatesStepInput = {
selector: FilterableTaxRateProps
update: UpdateTaxRateDTO
}

type WorkflowInput = UpdateTaxRatesStepInput

export const updateTaxRatesWorkflowId = "update-tax-rates"
export const updateTaxRatesWorkflow = createWorkflow(
updateTaxRatesWorkflowId,
(input: WorkflowData<WorkflowInput>): WorkflowData<TaxRateDTO[]> => {
return updateTaxRatesStep(input)
}
)
21 changes: 21 additions & 0 deletions packages/medusa/src/api-v2/admin/tax-rates/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@ import {

import { defaultAdminTaxRateFields } from "../query-config"
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { AdminPostTaxRatesTaxRateReq } from "../../../../api/routes/admin/tax-rates"
import { updateTaxRatesWorkflow } from "@medusajs/core-flows"

export const POST = async (
req: AuthenticatedMedusaRequest<AdminPostTaxRatesTaxRateReq>,
res: MedusaResponse
) => {
const { result, errors } = await updateTaxRatesWorkflow(req.scope).run({
input: {
selector: { id: req.params.id },
update: req.validatedBody,
},
throwOnError: false,
})

if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}

res.status(200).json({ tax_rate: result[0] })
}

export const GET = async (
req: AuthenticatedMedusaRequest,
Expand Down
6 changes: 6 additions & 0 deletions packages/medusa/src/api-v2/admin/tax-rates/middlewares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as QueryConfig from "./query-config"
import {
AdminGetTaxRatesTaxRateParams,
AdminPostTaxRatesReq,
AdminPostTaxRatesTaxRateReq,
} from "./validators"
import { transformBody, transformQuery } from "../../../api/middlewares"

Expand All @@ -20,6 +21,11 @@ export const adminTaxRateRoutesMiddlewares: MiddlewareRoute[] = [
matcher: "/admin/tax-rates",
middlewares: [transformBody(AdminPostTaxRatesReq)],
},
{
method: "POST",
matcher: "/admin/tax-rates/:id",
middlewares: [transformBody(AdminPostTaxRatesTaxRateReq)],
},
{
method: "GET",
matcher: "/admin/tax-rates/:id",
Expand Down
26 changes: 26 additions & 0 deletions packages/medusa/src/api-v2/admin/tax-rates/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,29 @@ export class AdminPostTaxRatesReq {
@IsOptional()
metadata?: Record<string, unknown>
}

export class AdminPostTaxRatesTaxRateReq {
@IsOptional()
@IsNumber()
rate?: number | null

@IsOptional()
@IsString()
code?: string | null

@IsString()
@IsOptional()
name?: string

@IsBoolean()
@IsOptional()
is_default?: boolean

@IsBoolean()
@IsOptional()
is_combinable?: boolean

@IsObject()
@IsOptional()
metadata?: Record<string, unknown>
}
21 changes: 21 additions & 0 deletions packages/tax/src/services/tax-module-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,27 @@ export default class TaxModuleService<
return await this.taxRateService_.update({ selector, data }, sharedContext)
}

async upsert(
data: TaxTypes.UpsertTaxRateDTO[],
sharedContext?: Context
): Promise<TaxTypes.TaxRateDTO[]>
async upsert(
data: TaxTypes.UpsertTaxRateDTO,
sharedContext?: Context
): Promise<TaxTypes.TaxRateDTO>

@InjectTransactionManager("baseRepository_")
async upsert(
data: TaxTypes.UpsertTaxRateDTO | TaxTypes.UpsertTaxRateDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TaxTypes.TaxRateDTO | TaxTypes.TaxRateDTO[]> {
const result = await this.taxRateService_.upsert(data, sharedContext)
const serialized = await this.baseRepository_.serialize<
TaxTypes.TaxRateDTO[]
>(result, { populate: true })
return Array.isArray(data) ? serialized : serialized[0]
}

createTaxRegions(
data: TaxTypes.CreateTaxRegionDTO,
sharedContext?: Context
Expand Down
10 changes: 10 additions & 0 deletions packages/types/src/tax/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ export interface CreateTaxRateDTO {
metadata?: Record<string, unknown>
}

export interface UpsertTaxRateDTO {
id?: string
rate?: number | null
code?: string | null
name?: string
is_default?: boolean
created_by?: string | null
metadata?: Record<string, unknown> | null
}

export interface UpdateTaxRateDTO {
rate?: number | null
code?: string | null
Expand Down
7 changes: 7 additions & 0 deletions packages/types/src/tax/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
CreateTaxRateDTO,
CreateTaxRegionDTO,
UpdateTaxRateDTO,
UpsertTaxRateDTO,
} from "./mutations"

export interface ITaxModuleService extends IModuleService {
Expand Down Expand Up @@ -63,6 +64,12 @@ export interface ITaxModuleService extends IModuleService {
sharedContext?: Context
): Promise<TaxRateDTO[]>

upsert(data: UpsertTaxRateDTO, sharedContext?: Context): Promise<TaxRateDTO>
upsert(
data: UpsertTaxRateDTO[],
sharedContext?: Context
): Promise<TaxRateDTO[]>

delete(taxRateIds: string[], sharedContext?: Context): Promise<void>
delete(taxRateId: string, sharedContext?: Context): Promise<void>

Expand Down

0 comments on commit ff50917

Please sign in to comment.