Skip to content

Commit

Permalink
schedule create metaobject in shopify
Browse files Browse the repository at this point in the history
  • Loading branch information
jamalsoueidan committed May 21, 2024
1 parent 4c63301 commit 0788f11
Show file tree
Hide file tree
Showing 8 changed files with 272 additions and 8 deletions.
4 changes: 2 additions & 2 deletions src/functions/customer/services/location/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,10 @@ export const CustomerLocationServiceUpdate = async (
])
);

if (body.metafieldId) {
if (updateLocation.metafieldId) {
await shopifyAdmin.request(UPDATE_LOCATION_METAOBJECT, {
variables: {
id: updateLocation.metafieldId || "",
id: updateLocation.metafieldId,
fields: [
{
key: "location_type",
Expand Down
85 changes: 84 additions & 1 deletion src/functions/customer/services/schedule/create.spec.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,101 @@
import { CustomerScheduleServiceCreate } from "./create";
import { ensureType } from "~/library/jest/helpers/mock";
import { shopifyAdmin } from "~/library/shopify";
import {
CreateScheduleMetaobjectMutation,
CreateScheduleMetaobjectMutationVariables,
} from "~/types/admin.generated";
import {
CREATE_SCHEDULE_METAOBJECT,
CustomerScheduleServiceCreate,
} from "./create";

require("~/library/jest/mongoose/mongodb.jest");

jest.mock("@shopify/admin-api-client", () => ({
createAdminApiClient: () => ({
request: jest.fn(),
}),
}));

const mockRequest = shopifyAdmin.request as jest.Mock;

describe("CustomerScheduleServiceCreate", () => {
const customerId = 123;
const name = "Test Schedule";

it("should create a new schedule", async () => {
mockRequest.mockResolvedValueOnce({
data: ensureType<CreateScheduleMetaobjectMutation>({
metaobjectCreate: {
metaobject: {
id: "gid://shopify/Metaobject/77850968391",
type: "schedule",
fields: [
{
value: name,
key: "name",
},
{
value: JSON.stringify([
{
day: "monday",
intervals: [
{
to: "16:00",
from: "08:00",
},
],
},
]),
key: "slots",
},
],
},
},
}),
});

const newSchedule = await CustomerScheduleServiceCreate({
name,
customerId,
});

expect(shopifyAdmin.request).toHaveBeenCalledTimes(1);

expect(shopifyAdmin.request).toHaveBeenNthCalledWith(
1,
CREATE_SCHEDULE_METAOBJECT,
{
variables: ensureType<CreateScheduleMetaobjectMutationVariables>({
handle: newSchedule._id,
fields: [
{
value: newSchedule.name,
key: "name",
},
{
value: JSON.stringify([
{
day: "monday",
intervals: [
{
to: "16:00",
from: "08:00",
},
],
},
]),
key: "slots",
},
],
}),
}
);

expect(newSchedule.name).toEqual(name);
expect(newSchedule.metafieldId).toEqual(
"gid://shopify/Metaobject/77850968391"
);
expect(newSchedule.customerId).toEqual(customerId);
});
});
39 changes: 38 additions & 1 deletion src/functions/customer/services/schedule/create.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Schedule, ScheduleModel } from "~/functions/schedule";
import { shopifyAdmin } from "~/library/shopify";

export type CustomerScheduleServiceCreateBody = Pick<
Schedule,
Expand All @@ -23,5 +24,41 @@ export const CustomerScheduleServiceCreate = async (
},
],
});
return newSchedule.save();
const scheduleModel = await newSchedule.save();

const { data } = await shopifyAdmin.request(CREATE_SCHEDULE_METAOBJECT, {
variables: {
handle: scheduleModel._id,
fields: [
{
key: "name",
value: scheduleModel.name,
},
{
key: "slots",
value: JSON.stringify(scheduleModel.slots),
},
],
},
});

scheduleModel.metafieldId = data?.metaobjectCreate?.metaobject?.id;
return scheduleModel.save();
};

export const CREATE_SCHEDULE_METAOBJECT = `#graphql
mutation CreateScheduleMetaobject($handle: String!, $fields: [MetaobjectFieldInput!]) {
metaobjectCreate(
metaobject: {type: "schedule", fields: $fields, handle: $handle, capabilities: {publishable: {status: ACTIVE}}}
) {
metaobject {
id
type
fields {
value
key
}
}
}
}
` as const;
101 changes: 97 additions & 4 deletions src/functions/customer/services/schedule/update.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,80 @@
import { ScheduleModel } from "~/functions/schedule";
import { NotFoundError } from "~/library/handler";
import { CustomerScheduleServiceCreate } from "./create";
import { CustomerScheduleServiceUpdate } from "./update";
import { ensureType } from "~/library/jest/helpers/mock";
import { shopifyAdmin } from "~/library/shopify";
import {
UpdateScheduleMetaobjectMutation,
UpdateScheduleMetaobjectMutationVariables,
} from "~/types/admin.generated";
import {
CustomerScheduleServiceUpdate,
UPDATE_SCHEDULE_METAOBJECT,
} from "./update";

require("~/library/jest/mongoose/mongodb.jest");

jest.mock("@shopify/admin-api-client", () => ({
createAdminApiClient: () => ({
request: jest.fn(),
}),
}));

const mockRequest = shopifyAdmin.request as jest.Mock;

describe("CustomerScheduleServiceUpdate", () => {
const customerId = 123;
const name = "Test Schedule";

it("should update schedule", async () => {
const newSchedule = await CustomerScheduleServiceCreate({
const newSchedule = new ScheduleModel({
name,
customerId,
metafieldId: "gid://shopify/Metaobject/77850968391",
slots: [
{
day: "monday",
intervals: [
{
from: "08:00",
to: "16:00",
},
],
},
],
});
await newSchedule.save();

const updatedScheduleName = "Updated Test Schedule";

mockRequest.mockResolvedValueOnce({
data: ensureType<UpdateScheduleMetaobjectMutation>({
metaobjectUpdate: {
metaobject: {
fields: [
{
value: name,
key: "name",
},
{
value: JSON.stringify([
{
day: "monday",
intervals: [
{
to: "16:00",
from: "08:00",
},
],
},
]),
key: "slots",
},
],
},
},
}),
});

const updatedSchedule = await CustomerScheduleServiceUpdate(
{
scheduleId: newSchedule._id,
Expand All @@ -24,16 +84,49 @@ describe("CustomerScheduleServiceUpdate", () => {
name: updatedScheduleName,
}
);

expect(shopifyAdmin.request).toHaveBeenCalledTimes(1);

expect(shopifyAdmin.request).toHaveBeenNthCalledWith(
1,
UPDATE_SCHEDULE_METAOBJECT,
{
variables: ensureType<UpdateScheduleMetaobjectMutationVariables>({
id: newSchedule.metafieldId || "",
fields: [
{
value: updatedScheduleName,
key: "name",
},
],
}),
}
);

expect(updatedSchedule).toMatchObject({
name: updatedScheduleName,
});
});

it("should throw NotFoundError when trying to update schedule that is not found", async () => {
const newSchedule = await CustomerScheduleServiceCreate({
const newSchedule = new ScheduleModel({
name,
customerId,
metafieldId: "gid://shopify/Metaobject/77850968391",
slots: [
{
day: "monday",
intervals: [
{
from: "08:00",
to: "16:00",
},
],
},
],
});
await newSchedule.save();

const updatedScheduleName = "Updated Test Schedule";

await expect(
Expand Down
28 changes: 28 additions & 0 deletions src/functions/customer/services/schedule/update.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Schedule, ScheduleModel } from "~/functions/schedule";
import { NotFoundError } from "~/library/handler";
import { shopifyAdmin } from "~/library/shopify";

export type ScheduleServiceUpdateProps = {
scheduleId: Schedule["_id"];
Expand Down Expand Up @@ -28,5 +29,32 @@ export const CustomerScheduleServiceUpdate = async (
])
);

if (updatedSchedule.metafieldId) {
await shopifyAdmin.request(UPDATE_SCHEDULE_METAOBJECT, {
variables: {
id: updatedSchedule.metafieldId,
fields: [
{
key: "name",
value: updatedSchedule.name,
},
],
},
});
}

return updatedSchedule;
};

export const UPDATE_SCHEDULE_METAOBJECT = `#graphql
mutation UpdateScheduleMetaobject($id: ID!, $fields: [MetaobjectFieldInput!]!) {
metaobjectUpdate(id: $id, metaobject: {fields: $fields}) {
metaobject {
fields {
value
key
}
}
}
}
` as const;
1 change: 1 addition & 0 deletions src/functions/schedule/schedule.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ export const ScheduleSlotsZodSchema = z
export const ScheduleZodSchema = z.object({
_id: StringOrObjectId,
name: z.string(),
metafieldId: z.string().optional(),
customerId: GidFormat,
slots: ScheduleSlotsZodSchema,
products: z.array(ScheduleProductZodSchema),
Expand Down
1 change: 1 addition & 0 deletions src/functions/schedule/schemas/schedule.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const ScheduleMongooseSchema = new Schema<
type: Number,
index: true,
},
metafieldId: String,
slots: [SlotSchema],
products: [ProductSchema],
},
Expand Down
21 changes: 21 additions & 0 deletions src/types/admin.generated.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,25 @@ export type ProductPricepdateMutation = { productVariantsBulkUpdate?: AdminTypes
& { variants: { nodes: Array<Pick<AdminTypes.ProductVariant, 'id' | 'compareAtPrice' | 'price'>> } }
)> }> };

export type CreateScheduleMetaobjectMutationVariables = AdminTypes.Exact<{
handle: AdminTypes.Scalars['String']['input'];
fields?: AdminTypes.InputMaybe<Array<AdminTypes.MetaobjectFieldInput> | AdminTypes.MetaobjectFieldInput>;
}>;


export type CreateScheduleMetaobjectMutation = { metaobjectCreate?: AdminTypes.Maybe<{ metaobject?: AdminTypes.Maybe<(
Pick<AdminTypes.Metaobject, 'id' | 'type'>
& { fields: Array<Pick<AdminTypes.MetaobjectField, 'value' | 'key'>> }
)> }> };

export type UpdateScheduleMetaobjectMutationVariables = AdminTypes.Exact<{
id: AdminTypes.Scalars['ID']['input'];
fields: Array<AdminTypes.MetaobjectFieldInput> | AdminTypes.MetaobjectFieldInput;
}>;


export type UpdateScheduleMetaobjectMutation = { metaobjectUpdate?: AdminTypes.Maybe<{ metaobject?: AdminTypes.Maybe<{ fields: Array<Pick<AdminTypes.MetaobjectField, 'value' | 'key'>> }> }> };

export type ProductVariantsBulkDeleteMutationVariables = AdminTypes.Exact<{
productId: AdminTypes.Scalars['ID']['input'];
variantsIds: Array<AdminTypes.Scalars['ID']['input']> | AdminTypes.Scalars['ID']['input'];
Expand Down Expand Up @@ -238,6 +257,8 @@ interface GeneratedMutationTypes {
"#graphql\n mutation productDestroy($productId: ID!) {\n productDelete(input: {id: $productId}) {\n deletedProductId\n }\n }\n": {return: ProductDestroyMutation, variables: ProductDestroyMutationVariables},
"#graphql\n #graphql\n fragment ProductFragment on Product {\n id\n handle\n tags\n title\n variants(first: 1) {\n nodes {\n id\n compareAtPrice\n price\n }\n }\n active: metafield(key: \"active\", namespace: \"system\") {\n id\n value\n }\n user: metafield(key: \"user\", namespace: \"booking\") {\n id\n value\n }\n hideFromCombine: metafield(key: \"hide_from_combine\", namespace: \"booking\") {\n id\n value\n }\n hideFromProfile: metafield(key: \"hide_from_profile\", namespace: \"booking\") {\n id\n value\n }\n parentId: metafield(key: \"parentId\", namespace: \"booking\") {\n id\n value\n }\n scheduleId: metafield(key: \"scheduleId\", namespace: \"booking\") {\n id\n value\n }\n locations: metafield(key: \"locations\", namespace: \"booking\") {\n id\n value\n }\n bookingPeriodValue: metafield(key: \"booking_period_value\", namespace: \"booking\") {\n id\n value\n }\n bookingPeriodUnit: metafield(key: \"booking_period_unit\", namespace: \"booking\") {\n id\n value\n }\n noticePeriodValue: metafield(key: \"notice_period_value\", namespace: \"booking\") {\n id\n value\n }\n noticePeriodUnit: metafield(key: \"notice_period_unit\", namespace: \"booking\") {\n id\n value\n }\n duration: metafield(key: \"duration\", namespace: \"booking\") {\n id\n value\n }\n breaktime: metafield(key: \"breaktime\", namespace: \"booking\") {\n id\n value\n }\n }\n\n mutation ProductUpdate($id: ID, $metafields: [MetafieldInput!], $tags: [String!], $title: String, $descriptionHtml: String) {\n productUpdate(input: {id: $id, metafields: $metafields, tags: $tags, title: $title, descriptionHtml: $descriptionHtml}) {\n product {\n ...ProductFragment\n }\n }\n }\n": {return: ProductUpdateMutation, variables: ProductUpdateMutationVariables},
"#graphql\n mutation productPricepdate($id: ID!, $variants: [ProductVariantsBulkInput!] = {}) {\n productVariantsBulkUpdate(\n productId: $id,\n variants: $variants\n ) {\n product {\n id\n variants(first: 1) {\n nodes {\n id\n compareAtPrice\n price\n }\n }\n }\n }\n }\n": {return: ProductPricepdateMutation, variables: ProductPricepdateMutationVariables},
"#graphql\n mutation CreateScheduleMetaobject($handle: String!, $fields: [MetaobjectFieldInput!]) {\n metaobjectCreate(\n metaobject: {type: \"schedule\", fields: $fields, handle: $handle, capabilities: {publishable: {status: ACTIVE}}}\n ) {\n metaobject {\n id\n type\n fields {\n value\n key\n }\n }\n }\n }\n": {return: CreateScheduleMetaobjectMutation, variables: CreateScheduleMetaobjectMutationVariables},
"#graphql\n mutation UpdateScheduleMetaobject($id: ID!, $fields: [MetaobjectFieldInput!]!) {\n metaobjectUpdate(id: $id, metaobject: {fields: $fields}) {\n metaobject {\n fields {\n value\n key\n }\n }\n }\n }\n": {return: UpdateScheduleMetaobjectMutation, variables: UpdateScheduleMetaobjectMutationVariables},
"#graphql\n mutation productVariantsBulkDelete($productId: ID!, $variantsIds: [ID!]!) {\n productVariantsBulkDelete(productId: $productId, variantsIds: $variantsIds) {\n product {\n id\n title\n }\n userErrors {\n code\n field\n message\n }\n }\n }\n": {return: ProductVariantsBulkDeleteMutation, variables: ProductVariantsBulkDeleteMutationVariables},
}
declare module '@shopify/admin-api-client' {
Expand Down

0 comments on commit 0788f11

Please sign in to comment.