fix/split providers (#271)

* refactor: ♻️ add explicit return to services

* refactor: ♻️ use provider get method

* refactor: ♻️ move obfuscation logic to router & separate public service

* build: 💚 add changeset
This commit is contained in:
Adrian Pilarczyk 2023-03-13 10:57:18 +01:00 committed by GitHub
parent 56a4dbb3a3
commit b46a9f3e70
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 154 additions and 209 deletions

View file

@ -0,0 +1,5 @@
---
"saleor-app-taxes": patch
---
Fix the create provider error. Add explicit return types to configuration services. Move obfuscating logic to routers and public services.

View file

@ -1,4 +1,5 @@
import { z } from "zod"; import { z } from "zod";
import { obfuscateSecret } from "../../lib/utils";
export const avataxConfigSchema = z.object({ export const avataxConfigSchema = z.object({
name: z.string().min(1, { message: "Name requires at least one character." }), name: z.string().min(1, { message: "Name requires at least one character." }),
@ -27,3 +28,15 @@ export const avataxInstanceConfigSchema = z.object({
}); });
export type AvataxInstanceConfig = z.infer<typeof avataxInstanceConfigSchema>; export type AvataxInstanceConfig = z.infer<typeof avataxInstanceConfigSchema>;
export const obfuscateAvataxConfig = (config: AvataxConfig) => ({
...config,
username: obfuscateSecret(config.username),
password: obfuscateSecret(config.password),
});
export const obfuscateAvataxInstances = (instances: AvataxInstanceConfig[]) =>
instances.map((instance) => ({
...instance,
config: obfuscateAvataxConfig(instance.config),
}));

View file

@ -1,8 +1,9 @@
import { z } from "zod"; import { z } from "zod";
import { logger as pinoLogger } from "../../lib/logger"; import { logger as pinoLogger } from "../../lib/logger";
import { isObfuscated } from "../../lib/utils";
import { protectedClientProcedure } from "../trpc/protected-client-procedure"; import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { router } from "../trpc/trpc-server"; import { router } from "../trpc/trpc-server";
import { avataxConfigSchema } from "./avatax-config"; import { avataxConfigSchema, obfuscateAvataxConfig } from "./avatax-config";
import { AvataxConfigurationService } from "./avatax-configuration.service"; import { AvataxConfigurationService } from "./avatax-configuration.service";
const getInputSchema = z.object({ const getInputSchema = z.object({
@ -15,12 +16,14 @@ const deleteInputSchema = z.object({
const patchInputSchema = z.object({ const patchInputSchema = z.object({
id: z.string(), id: z.string(),
value: avataxConfigSchema.partial(), value: avataxConfigSchema.partial().transform((c) => {
}); const { username, password, ...config } = c ?? {};
return {
const putInputSchema = z.object({ ...config,
id: z.string(), ...(username && !isObfuscated(username) && { username }),
value: avataxConfigSchema, ...(password && !isObfuscated(password) && { password }),
};
}),
}); });
const postInputSchema = z.object({ const postInputSchema = z.object({
@ -43,7 +46,7 @@ export const avataxConfigurationRouter = router({
logger.debug({ result }, "avataxConfigurationRouter.get finished"); logger.debug({ result }, "avataxConfigurationRouter.get finished");
return result; return { ...result, config: obfuscateAvataxConfig(result.config) };
}), }),
post: protectedClientProcedure.input(postInputSchema).mutation(async ({ ctx, input }) => { post: protectedClientProcedure.input(postInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ const logger = pinoLogger.child({
@ -94,23 +97,6 @@ export const avataxConfigurationRouter = router({
logger.debug({ result }, "avataxConfigurationRouter.patch finished"); logger.debug({ result }, "avataxConfigurationRouter.patch finished");
return result;
}),
put: protectedClientProcedure.input(putInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "avataxConfigurationRouter.put",
});
logger.debug("avataxConfigurationRouter.put called");
const { apiClient, saleorApiUrl } = ctx;
const avataxConfigurationService = new AvataxConfigurationService(apiClient, saleorApiUrl);
const result = await avataxConfigurationService.put(input.id, input.value);
logger.debug({ result }, "avataxConfigurationRouter.put finished");
return result; return result;
}), }),
}); });

View file

@ -1,54 +1,14 @@
import pino from "pino"; import pino from "pino";
import { Client } from "urql"; import { Client } from "urql";
import { createLogger } from "../../lib/logger"; import { createLogger } from "../../lib/logger";
import { isObfuscated, obfuscateSecret } from "../../lib/utils";
import { createSettingsManager } from "../app-configuration/metadata-manager"; import { createSettingsManager } from "../app-configuration/metadata-manager";
import { CrudSettingsConfigurator } from "../crud-settings/crud-settings.service"; import { CrudSettingsConfigurator } from "../crud-settings/crud-settings.service";
import { providersSchema } from "../providers-configuration/providers-config"; import { providersSchema } from "../providers-configuration/providers-config";
import { TAX_PROVIDER_KEY } from "../providers-configuration/providers-configuration-service"; import { TAX_PROVIDER_KEY } from "../providers-configuration/public-providers-configuration-service";
import { AvataxClient } from "./avatax-client"; import { AvataxClient } from "./avatax-client";
import { import { AvataxConfig, AvataxInstanceConfig, avataxInstanceConfigSchema } from "./avatax-config";
AvataxConfig,
avataxConfigSchema,
AvataxInstanceConfig,
avataxInstanceConfigSchema,
} from "./avatax-config";
const obfuscateConfig = (config: AvataxConfig) => ({
...config,
username: obfuscateSecret(config.username),
password: obfuscateSecret(config.password),
});
const obfuscateProvidersConfig = (instances: AvataxInstanceConfig[]) =>
instances.map((instance) => ({
...instance,
config: obfuscateConfig(instance.config),
}));
const getSchema = avataxInstanceConfigSchema.transform((instance) => ({
...instance,
config: obfuscateConfig(instance.config),
}));
const patchSchema = avataxConfigSchema.partial().transform((c) => {
const { username, password, ...config } = c ?? {};
return {
...config,
...(username && !isObfuscated(username) && { username }),
...(password && !isObfuscated(password) && { password }),
};
});
const putSchema = avataxConfigSchema.transform((c) => {
const { username, password, ...config } = c;
return {
...config,
...(!isObfuscated(username) && { username }),
...(!isObfuscated(password) && { password }),
};
});
const getSchema = avataxInstanceConfigSchema;
export class AvataxConfigurationService { export class AvataxConfigurationService {
private crudSettingsConfigurator: CrudSettingsConfigurator; private crudSettingsConfigurator: CrudSettingsConfigurator;
private logger: pino.Logger; private logger: pino.Logger;
@ -65,7 +25,7 @@ export class AvataxConfigurationService {
}); });
} }
async getAll() { async getAll(): Promise<AvataxInstanceConfig[]> {
this.logger.debug(".getAll called"); this.logger.debug(".getAll called");
const { data } = await this.crudSettingsConfigurator.readAll(); const { data } = await this.crudSettingsConfigurator.readAll();
const validation = providersSchema.safeParse(data); const validation = providersSchema.safeParse(data);
@ -79,10 +39,10 @@ export class AvataxConfigurationService {
(instance) => instance.provider === "avatax" (instance) => instance.provider === "avatax"
) as AvataxInstanceConfig[]; ) as AvataxInstanceConfig[];
return obfuscateProvidersConfig(instances); return instances;
} }
async get(id: string) { async get(id: string): Promise<AvataxInstanceConfig> {
this.logger.debug(`.get called with id: ${id}`); this.logger.debug(`.get called with id: ${id}`);
const { data } = await this.crudSettingsConfigurator.read(id); const { data } = await this.crudSettingsConfigurator.read(id);
this.logger.debug({ setting: data }, `Fetched setting from crudSettingsConfigurator`); this.logger.debug({ setting: data }, `Fetched setting from crudSettingsConfigurator`);
@ -97,7 +57,7 @@ export class AvataxConfigurationService {
return validation.data; return validation.data;
} }
async post(config: AvataxConfig) { async post(config: AvataxConfig): Promise<{ id: string }> {
this.logger.debug(`.post called with value: ${JSON.stringify(config)}`); this.logger.debug(`.post called with value: ${JSON.stringify(config)}`);
const avataxClient = new AvataxClient(config); const avataxClient = new AvataxClient(config);
const validation = await avataxClient.ping(); const validation = await avataxClient.ping();
@ -106,45 +66,40 @@ export class AvataxConfigurationService {
this.logger.error(validation.error); this.logger.error(validation.error);
throw new Error(validation.error); throw new Error(validation.error);
} }
const result = await this.crudSettingsConfigurator.create({
provider: "avatax",
config: config,
});
return result.data;
} }
async patch(id: string, config: Partial<AvataxConfig>) { async patch(id: string, config: Partial<AvataxConfig>): Promise<void> {
this.logger.debug(`.patch called with id: ${id} and value: ${JSON.stringify(config)}`); this.logger.debug(`.patch called with id: ${id} and value: ${JSON.stringify(config)}`);
const result = await this.get(id); const data = await this.get(id);
// omit the key "id" from the result // omit the key "id" from the result
const { id: _, ...setting } = result; const { id: _, ...setting } = data;
const validation = patchSchema.safeParse(config);
if (!validation.success) {
this.logger.error({ error: validation.error.format() }, "Validation error while patch");
throw new Error(validation.error.message);
}
return this.crudSettingsConfigurator.update(id, { return this.crudSettingsConfigurator.update(id, {
...setting, ...setting,
config: { ...setting.config, ...validation.data }, config: { ...setting.config, ...config },
}); });
} }
async put(id: string, config: AvataxConfig) { async put(id: string, config: AvataxConfig): Promise<void> {
const result = await this.get(id); const data = await this.get(id);
// omit the key "id" from the result // omit the key "id" from the result
const { id: _, ...setting } = result; const { id: _, ...setting } = data;
const validation = putSchema.safeParse(config);
if (!validation.success) {
this.logger.error({ error: validation.error.format() }, "Validation error while patch");
throw new Error(validation.error.message);
}
this.logger.debug(`.put called with id: ${id} and value: ${JSON.stringify(config)}`); this.logger.debug(`.put called with id: ${id} and value: ${JSON.stringify(config)}`);
return this.crudSettingsConfigurator.update(id, { return this.crudSettingsConfigurator.update(id, {
...setting, ...setting,
config: { ...validation.data }, config: { ...config },
}); });
} }
async delete(id: string) { async delete(id: string): Promise<void> {
this.logger.debug(`.delete called with id: ${id}`); this.logger.debug(`.delete called with id: ${id}`);
return this.crudSettingsConfigurator.delete(id); return this.crudSettingsConfigurator.delete(id);
} }

View file

@ -13,10 +13,10 @@ import { Button, makeStyles } from "@saleor/macaw-ui";
import React from "react"; import React from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { z } from "zod"; import { z } from "zod";
import { useInstanceId } from "../../taxes/tax-context";
import { trpcClient } from "../../trpc/trpc-client"; import { trpcClient } from "../../trpc/trpc-client";
import { AppLink } from "../../ui/app-link"; import { AppLink } from "../../ui/app-link";
import { useInstanceId } from "../../taxes/tax-context"; import { avataxConfigSchema } from "../avatax-config";
import { avataxConfigSchema, avataxInstanceConfigSchema } from "../avatax-config";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
reverseRow: { reverseRow: {
@ -59,8 +59,12 @@ export const AvataxConfigurationForm = () => {
); );
}, },
}); });
const { data: providersConfig, refetch: refetchProvidersConfigurationData } = const { refetch: refetchProvidersConfigurationData } =
trpcClient.providersConfiguration.getAll.useQuery(undefined, { trpcClient.providersConfiguration.getAll.useQuery();
const { data: instance } = trpcClient.avataxConfiguration.get.useQuery(
{ id: instanceId ?? "" },
{
enabled: !!instanceId,
onError(error) { onError(error) {
appBridge?.dispatch( appBridge?.dispatch(
actions.Notification({ actions.Notification({
@ -70,9 +74,8 @@ export const AvataxConfigurationForm = () => {
}) })
); );
}, },
}); }
);
const instance = providersConfig?.find((instance) => instance.id === instanceId);
const resetInstanceId = () => { const resetInstanceId = () => {
setInstanceId(null); setInstanceId(null);
@ -89,7 +92,7 @@ export const AvataxConfigurationForm = () => {
const { mutate: createMutation, isLoading: isCreateLoading } = const { mutate: createMutation, isLoading: isCreateLoading } =
trpcClient.avataxConfiguration.post.useMutation({ trpcClient.avataxConfiguration.post.useMutation({
onSuccess({ data: { id } }) { onSuccess({ id }) {
setInstanceId(id); setInstanceId(id);
refetchProvidersConfigurationData(); refetchProvidersConfigurationData();
appBridge?.dispatch( appBridge?.dispatch(

View file

@ -6,7 +6,7 @@ import { TaxJarConfigurationService } from "../taxjar/taxjar-configuration.servi
export const TAX_PROVIDER_KEY = "tax-providers"; export const TAX_PROVIDER_KEY = "tax-providers";
export class TaxProvidersConfigurationService { export class PrivateTaxProvidersConfigurationService {
private avataxConfigurationService: AvataxConfigurationService; private avataxConfigurationService: AvataxConfigurationService;
private taxJarConfigurationService: TaxJarConfigurationService; private taxJarConfigurationService: TaxJarConfigurationService;
private logger: pino.Logger; private logger: pino.Logger;
@ -14,7 +14,7 @@ export class TaxProvidersConfigurationService {
this.avataxConfigurationService = new AvataxConfigurationService(client, saleorApiUrl); this.avataxConfigurationService = new AvataxConfigurationService(client, saleorApiUrl);
this.taxJarConfigurationService = new TaxJarConfigurationService(client, saleorApiUrl); this.taxJarConfigurationService = new TaxJarConfigurationService(client, saleorApiUrl);
this.logger = createLogger({ this.logger = createLogger({
service: "TaxProvidersConfigurationService", service: "PrivateTaxProvidersConfigurationService",
metadataKey: TAX_PROVIDER_KEY, metadataKey: TAX_PROVIDER_KEY,
}); });
} }
@ -23,7 +23,6 @@ export class TaxProvidersConfigurationService {
this.logger.debug(".getAll called"); this.logger.debug(".getAll called");
const taxJar = await this.taxJarConfigurationService.getAll(); const taxJar = await this.taxJarConfigurationService.getAll();
const avatax = await this.avataxConfigurationService.getAll(); const avatax = await this.avataxConfigurationService.getAll();
// todo: add more clever way of joining the two. Maybe add updated_at date to the config and use it to sort?
return [...taxJar, ...avatax]; return [...taxJar, ...avatax];
} }
} }

View file

@ -1,7 +1,7 @@
import { logger as pinoLogger } from "../../lib/logger"; import { logger as pinoLogger } from "../../lib/logger";
import { protectedClientProcedure } from "../trpc/protected-client-procedure"; import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { router } from "../trpc/trpc-server"; import { router } from "../trpc/trpc-server";
import { TaxProvidersConfigurationService } from "./providers-configuration-service"; import { PublicTaxProvidersConfigurationService } from "./public-providers-configuration-service";
export const providersConfigurationRouter = router({ export const providersConfigurationRouter = router({
getAll: protectedClientProcedure.query(async ({ ctx }) => { getAll: protectedClientProcedure.query(async ({ ctx }) => {
@ -9,6 +9,6 @@ export const providersConfigurationRouter = router({
logger.debug("providersConfigurationRouter.fetch called"); logger.debug("providersConfigurationRouter.fetch called");
return new TaxProvidersConfigurationService(ctx.apiClient, ctx.saleorApiUrl).getAll(); return new PublicTaxProvidersConfigurationService(ctx.apiClient, ctx.saleorApiUrl).getAll();
}), }),
}); });

View file

@ -0,0 +1,30 @@
import pino from "pino";
import { Client } from "urql";
import { createLogger } from "../../lib/logger";
import { obfuscateAvataxInstances } from "../avatax/avatax-config";
import { AvataxConfigurationService } from "../avatax/avatax-configuration.service";
import { obfuscateTaxJarInstances } from "../taxjar/taxjar-config";
import { TaxJarConfigurationService } from "../taxjar/taxjar-configuration.service";
export const TAX_PROVIDER_KEY = "tax-providers";
export class PublicTaxProvidersConfigurationService {
private avataxConfigurationService: AvataxConfigurationService;
private taxJarConfigurationService: TaxJarConfigurationService;
private logger: pino.Logger;
constructor(client: Client, saleorApiUrl: string) {
this.avataxConfigurationService = new AvataxConfigurationService(client, saleorApiUrl);
this.taxJarConfigurationService = new TaxJarConfigurationService(client, saleorApiUrl);
this.logger = createLogger({
service: "PublicTaxProvidersConfigurationService",
metadataKey: TAX_PROVIDER_KEY,
});
}
async getAll() {
this.logger.debug(".getAll called");
const taxJar = await this.taxJarConfigurationService.getAll();
const avatax = await this.avataxConfigurationService.getAll();
return [...obfuscateTaxJarInstances(taxJar), ...obfuscateAvataxInstances(avatax)];
}
}

View file

@ -21,3 +21,14 @@ export const taxJarInstanceConfigSchema = z.object({
}); });
export type TaxJarInstanceConfig = z.infer<typeof taxJarInstanceConfigSchema>; export type TaxJarInstanceConfig = z.infer<typeof taxJarInstanceConfigSchema>;
export const obfuscateTaxJarConfig = (config: TaxJarConfig) => ({
...config,
apiKey: obfuscateSecret(config.apiKey),
});
export const obfuscateTaxJarInstances = (instances: TaxJarInstanceConfig[]) =>
instances.map((instance) => ({
...instance,
config: obfuscateTaxJarConfig(instance.config),
}));

View file

@ -1,8 +1,9 @@
import { z } from "zod"; import { z } from "zod";
import { logger as pinoLogger } from "../../lib/logger"; import { logger as pinoLogger } from "../../lib/logger";
import { isObfuscated } from "../../lib/utils";
import { protectedClientProcedure } from "../trpc/protected-client-procedure"; import { protectedClientProcedure } from "../trpc/protected-client-procedure";
import { router } from "../trpc/trpc-server"; import { router } from "../trpc/trpc-server";
import { taxJarConfigSchema } from "./taxjar-config"; import { obfuscateTaxJarConfig, taxJarConfigSchema } from "./taxjar-config";
import { TaxJarConfigurationService } from "./taxjar-configuration.service"; import { TaxJarConfigurationService } from "./taxjar-configuration.service";
const getInputSchema = z.object({ const getInputSchema = z.object({
@ -15,12 +16,13 @@ const deleteInputSchema = z.object({
const patchInputSchema = z.object({ const patchInputSchema = z.object({
id: z.string(), id: z.string(),
value: taxJarConfigSchema.partial(), value: taxJarConfigSchema.partial().transform((c) => {
}); const { apiKey, ...config } = c ?? {};
return {
const putInputSchema = z.object({ ...config,
id: z.string(), ...(apiKey && !isObfuscated(apiKey) && { apiKey }),
value: taxJarConfigSchema, };
}),
}); });
const postInputSchema = z.object({ const postInputSchema = z.object({
@ -43,7 +45,7 @@ export const taxjarConfigurationRouter = router({
logger.debug({ result }, "taxjarConfigurationRouter.get finished"); logger.debug({ result }, "taxjarConfigurationRouter.get finished");
return result; return { ...result, config: obfuscateTaxJarConfig(result.config) };
}), }),
post: protectedClientProcedure.input(postInputSchema).mutation(async ({ ctx, input }) => { post: protectedClientProcedure.input(postInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({ const logger = pinoLogger.child({
@ -94,23 +96,6 @@ export const taxjarConfigurationRouter = router({
logger.debug({ result }, "taxjarConfigurationRouter.patch finished"); logger.debug({ result }, "taxjarConfigurationRouter.patch finished");
return result;
}),
put: protectedClientProcedure.input(putInputSchema).mutation(async ({ ctx, input }) => {
const logger = pinoLogger.child({
saleorApiUrl: ctx.saleorApiUrl,
procedure: "taxjarConfigurationRouter.put",
});
logger.debug("taxjarConfigurationRouter.put called");
const { apiClient, saleorApiUrl } = ctx;
const taxjarConfigurationService = new TaxJarConfigurationService(apiClient, saleorApiUrl);
const result = await taxjarConfigurationService.put(input.id, input.value);
logger.debug({ result }, "taxjarConfigurationRouter.put finished");
return result; return result;
}), }),
}); });

View file

@ -1,50 +1,14 @@
import pino from "pino"; import pino from "pino";
import { Client } from "urql"; import { Client } from "urql";
import { createLogger } from "../../lib/logger"; import { createLogger } from "../../lib/logger";
import { isObfuscated, obfuscateSecret } from "../../lib/utils";
import { createSettingsManager } from "../app-configuration/metadata-manager"; import { createSettingsManager } from "../app-configuration/metadata-manager";
import { CrudSettingsConfigurator } from "../crud-settings/crud-settings.service"; import { CrudSettingsConfigurator } from "../crud-settings/crud-settings.service";
import { providersSchema } from "../providers-configuration/providers-config"; import { providersSchema } from "../providers-configuration/providers-config";
import { TAX_PROVIDER_KEY } from "../providers-configuration/providers-configuration-service"; import { TAX_PROVIDER_KEY } from "../providers-configuration/public-providers-configuration-service";
import { TaxJarClient } from "./taxjar-client"; import { TaxJarClient } from "./taxjar-client";
import { import { TaxJarConfig, TaxJarInstanceConfig, taxJarInstanceConfigSchema } from "./taxjar-config";
TaxJarConfig,
taxJarConfigSchema,
TaxJarInstanceConfig,
taxJarInstanceConfigSchema,
} from "./taxjar-config";
const obfuscateConfig = (config: TaxJarConfig) => ({ const getSchema = taxJarInstanceConfigSchema;
...config,
apiKey: obfuscateSecret(config.apiKey),
});
const obfuscateProvidersConfig = (instances: TaxJarInstanceConfig[]) =>
instances.map((instance) => ({
...instance,
config: obfuscateConfig(instance.config),
}));
const getSchema = taxJarInstanceConfigSchema.transform((instance) => ({
...instance,
config: obfuscateConfig(instance.config),
}));
const patchSchema = taxJarConfigSchema.partial().transform((c) => {
const { apiKey, ...config } = c ?? {};
return {
...config,
...(apiKey && !isObfuscated(apiKey) && { apiKey }),
};
});
const putSchema = taxJarConfigSchema.transform((c) => {
const { apiKey, ...config } = c;
return {
...config,
...(!isObfuscated(apiKey) && { apiKey }),
};
});
export class TaxJarConfigurationService { export class TaxJarConfigurationService {
private crudSettingsConfigurator: CrudSettingsConfigurator; private crudSettingsConfigurator: CrudSettingsConfigurator;
@ -62,7 +26,7 @@ export class TaxJarConfigurationService {
}); });
} }
async getAll() { async getAll(): Promise<TaxJarInstanceConfig[]> {
this.logger.debug(".getAll called"); this.logger.debug(".getAll called");
const { data } = await this.crudSettingsConfigurator.readAll(); const { data } = await this.crudSettingsConfigurator.readAll();
this.logger.debug({ settings: data }, `Fetched settings from crudSettingsConfigurator`); this.logger.debug({ settings: data }, `Fetched settings from crudSettingsConfigurator`);
@ -77,12 +41,12 @@ export class TaxJarConfigurationService {
(instance) => instance.provider === "taxjar" (instance) => instance.provider === "taxjar"
) as TaxJarInstanceConfig[]; ) as TaxJarInstanceConfig[];
return obfuscateProvidersConfig(instances); return instances;
} }
async get(id: string) { async get(id: string): Promise<TaxJarInstanceConfig> {
this.logger.debug(`.get called with id: ${id}`); this.logger.debug(`.get called with id: ${id}`);
const { data } = await this.crudSettingsConfigurator.read(id); const data = await this.crudSettingsConfigurator.read(id);
this.logger.debug({ setting: data }, `Fetched setting from crudSettingsConfigurator`); this.logger.debug({ setting: data }, `Fetched setting from crudSettingsConfigurator`);
const validation = getSchema.safeParse(data); const validation = getSchema.safeParse(data);
@ -95,7 +59,7 @@ export class TaxJarConfigurationService {
return validation.data; return validation.data;
} }
async post(config: TaxJarConfig) { async post(config: TaxJarConfig): Promise<{ id: string }> {
this.logger.debug(`.post called with value: ${JSON.stringify(config)}`); this.logger.debug(`.post called with value: ${JSON.stringify(config)}`);
const taxJarClient = new TaxJarClient(config); const taxJarClient = new TaxJarClient(config);
const validation = await taxJarClient.ping(); const validation = await taxJarClient.ping();
@ -104,49 +68,39 @@ export class TaxJarConfigurationService {
this.logger.error({ error: validation.error }, "Validation error while post"); this.logger.error({ error: validation.error }, "Validation error while post");
throw new Error(validation.error); throw new Error(validation.error);
} }
return this.crudSettingsConfigurator.create({ const result = await this.crudSettingsConfigurator.create({
provider: "taxjar", provider: "taxjar",
config: config, config: config,
}); });
return result.data;
} }
async patch(id: string, config: Partial<TaxJarConfig>) { async patch(id: string, config: Partial<TaxJarConfig>): Promise<void> {
this.logger.debug(`.patch called with id: ${id} and value: ${JSON.stringify(config)}`); this.logger.debug(`.patch called with id: ${id} and value: ${JSON.stringify(config)}`);
const result = await this.get(id); const data = await this.get(id);
// omit the key "id" from the result // omit the key "id" from the result
const { id: _, ...setting } = result; const { id: _, ...setting } = data;
const validation = patchSchema.safeParse(config);
if (!validation.success) {
this.logger.error({ error: validation.error.format() }, "Validation error while patch");
throw new Error(validation.error.message);
}
return this.crudSettingsConfigurator.update(id, { return this.crudSettingsConfigurator.update(id, {
...setting, ...setting,
config: { ...setting.config, ...validation.data }, config: { ...setting.config, ...config },
}); });
} }
async put(id: string, config: TaxJarConfig) { async put(id: string, config: TaxJarConfig): Promise<void> {
const result = await this.get(id); const data = await this.get(id);
// omit the key "id" from the result // omit the key "id" from the result
const { id: _, ...setting } = result; const { id: _, ...setting } = data;
const validation = putSchema.safeParse(config);
if (!validation.success) {
this.logger.error({ error: validation.error.format() }, "Validation error while patch");
throw new Error(validation.error.message);
}
this.logger.debug(`.put called with id: ${id} and value: ${JSON.stringify(config)}`); this.logger.debug(`.put called with id: ${id} and value: ${JSON.stringify(config)}`);
return this.crudSettingsConfigurator.update(id, { return this.crudSettingsConfigurator.update(id, {
...setting, ...setting,
config: { ...validation.data }, config: { ...config },
}); });
} }
async delete(id: string) { async delete(id: string): Promise<void> {
this.logger.debug(`.delete called with id: ${id}`); this.logger.debug(`.delete called with id: ${id}`);
return this.crudSettingsConfigurator.delete(id); return this.crudSettingsConfigurator.delete(id);
} }

View file

@ -13,9 +13,9 @@ import { Button, makeStyles } from "@saleor/macaw-ui";
import React from "react"; import React from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { z } from "zod"; import { z } from "zod";
import { trpcClient } from "../../trpc/trpc-client";
import { useInstanceId } from "../../taxes/tax-context"; import { useInstanceId } from "../../taxes/tax-context";
import { taxJarConfigSchema, taxJarInstanceConfigSchema } from "../taxjar-config"; import { trpcClient } from "../../trpc/trpc-client";
import { taxJarConfigSchema } from "../taxjar-config";
const useStyles = makeStyles((theme) => ({ const useStyles = makeStyles((theme) => ({
reverseRow: { reverseRow: {
@ -61,8 +61,12 @@ export const TaxJarConfigurationForm = () => {
}, },
}); });
const { data: providersConfigurationData, refetch: refetchProvidersConfigurationData } = const { refetch: refetchProvidersConfigurationData } =
trpcClient.providersConfiguration.getAll.useQuery(undefined, { trpcClient.providersConfiguration.getAll.useQuery();
const { data: instance } = trpcClient.avataxConfiguration.get.useQuery(
{ id: instanceId ?? "" },
{
enabled: !!instanceId,
onError(error) { onError(error) {
appBridge?.dispatch( appBridge?.dispatch(
actions.Notification({ actions.Notification({
@ -72,13 +76,12 @@ export const TaxJarConfigurationForm = () => {
}) })
); );
}, },
}); }
);
const instance = providersConfigurationData?.find((instance) => instance.id === instanceId);
const { mutate: createMutation, isLoading: isCreateLoading } = const { mutate: createMutation, isLoading: isCreateLoading } =
trpcClient.taxJarConfiguration.post.useMutation({ trpcClient.taxJarConfiguration.post.useMutation({
onSuccess({ data: { id } }) { onSuccess({ id }) {
setInstanceId(id); setInstanceId(id);
refetchProvidersConfigurationData(); refetchProvidersConfigurationData();
refetchChannelConfigurationData(); refetchChannelConfigurationData();

View file

@ -5,7 +5,8 @@ import { createClient } from "../../../lib/graphql";
import { createLogger } from "../../../lib/logger"; import { createLogger } from "../../../lib/logger";
import { calculateTaxesPayloadSchema, ExpectedWebhookPayload } from "../../../lib/saleor/schema"; import { calculateTaxesPayloadSchema, ExpectedWebhookPayload } from "../../../lib/saleor/schema";
import { GetChannelsConfigurationService } from "../../../modules/channels-configuration/get-channels-configuration.service"; import { GetChannelsConfigurationService } from "../../../modules/channels-configuration/get-channels-configuration.service";
import { TaxProvidersConfigurationService } from "../../../modules/providers-configuration/providers-configuration-service"; import { PrivateTaxProvidersConfigurationService } from "../../../modules/providers-configuration/private-providers-configuration-service";
import { ActiveTaxProvider } from "../../../modules/taxes/active-tax-provider"; import { ActiveTaxProvider } from "../../../modules/taxes/active-tax-provider";
export const config = { export const config = {
@ -43,7 +44,7 @@ export default checkoutCalculateTaxesSyncWebhook.createHandler(async (req, res,
Promise.resolve({ token: authData.token }) Promise.resolve({ token: authData.token })
); );
const providersConfig = await new TaxProvidersConfigurationService( const providersConfig = await new PrivateTaxProvidersConfigurationService(
client, client,
authData.saleorApiUrl authData.saleorApiUrl
).getAll(); ).getAll();

View file

@ -5,7 +5,7 @@ import { createClient } from "../../../lib/graphql";
import { createLogger } from "../../../lib/logger"; import { createLogger } from "../../../lib/logger";
import { calculateTaxesPayloadSchema, ExpectedWebhookPayload } from "../../../lib/saleor/schema"; import { calculateTaxesPayloadSchema, ExpectedWebhookPayload } from "../../../lib/saleor/schema";
import { GetChannelsConfigurationService } from "../../../modules/channels-configuration/get-channels-configuration.service"; import { GetChannelsConfigurationService } from "../../../modules/channels-configuration/get-channels-configuration.service";
import { TaxProvidersConfigurationService } from "../../../modules/providers-configuration/providers-configuration-service"; import { PrivateTaxProvidersConfigurationService } from "../../../modules/providers-configuration/private-providers-configuration-service";
import { ActiveTaxProvider } from "../../../modules/taxes/active-tax-provider"; import { ActiveTaxProvider } from "../../../modules/taxes/active-tax-provider";
export const config = { export const config = {
@ -42,7 +42,7 @@ export default orderCalculateTaxesSyncWebhook.createHandler(async (req, res, ctx
const client = createClient(authData.saleorApiUrl, async () => const client = createClient(authData.saleorApiUrl, async () =>
Promise.resolve({ token: authData.token }) Promise.resolve({ token: authData.token })
); );
const providersConfig = await new TaxProvidersConfigurationService( const providersConfig = await new PrivateTaxProvidersConfigurationService(
client, client,
authData.saleorApiUrl authData.saleorApiUrl
).getAll(); ).getAll();