Hi @Bryan-Square ,
As requested, Please refer to “getListSubscriptionPlan()” in below square.service.ts complete code where we called list catalog api
Here we used process.env.SQUARE_API_VERSION over code and find the .env setup code as below
.env
# PRODUCTION SQUARE PAYMENT GATEWAY
SQUARE_URL=https://connect.squareup.com
SQUARE_APPLI_ID=sq0idp-HR_b0xXg8Q6vl4Pl7gwOJg
SQUARE_ACCESS_TOKEN=Exxxxxxxxxxxxxxxxxxxxxxx
SQUARE_API_VERSION=2023-12-13
LOCATION_ID=L016J6TZKPE5A
square.service.ts
import { Injectable } from "@nestjs/common";
import axios from "axios";
import * as crypto from "crypto";
import * as moment from "moment";
import { Client, Environment } from "square";
import { PaymentSubscriptionService } from "src/payment-subscription/payment-subscription.service";
export interface IPublishInput {
/**
* Recipent Name
*/
cardholder_name;
/**
* Card Last 4 digit
*/
last_4;
/**
* Card Expiry Month
*/
exp_month;
/**
* Card Expiry Year
*/
exp_year;
/**
* Payment Amount
*/
amount;
/**
* Agent Id
*/
agentId;
/**
* Buyer Id
*/
buyerId;
/**
* Subscription Type
*/
subscription_type;
}
@Injectable()
export class SquareService {
constructor(private readonly paymentSubscriptionService: PaymentSubscriptionService) { }
headers = {
headers: {
"Square-Version": process.env.SQUARE_API_VERSION,
Authorization: `Bearer ${process.env.SQUARE_ACCESS_TOKEN}`,
"Content-Type": "application/json"
}
};
async createPayment(cardholder_name, nonce, amount, agentId, buyerId, subscription_type) {
try {
const idempotency_key = crypto.randomBytes(22).toString("hex");
const customerRes = await axios.post(
`${process.env.SQUARE_URL}/v2/customers`,
{
email_address: process.env.SQUARE_EMAIL
},
this.headers
);
let paymentRes: any;
if (customerRes?.data) {
/* Make Payments */
paymentRes = await axios.post(
`${process.env.SQUARE_URL}/v2/payments`,
{
idempotency_key: idempotency_key,
amount_money: {
amount: parseInt(amount),
currency: "USD"
},
source_id: nonce,
autocomplete: true
},
this.headers
);
if (paymentRes?.data) {
const cardData = {
card_id: paymentRes?.data?.payment?.id,
card_brand: paymentRes?.data?.payment?.card_details?.card?.card_brand,
last_4: paymentRes?.data?.payment?.card_details?.card?.last_4,
exp_month: paymentRes?.data?.payment?.card_details?.card?.exp_month,
exp_year: paymentRes?.data?.payment?.card_details?.card?.exp_year,
cardholder_name: cardholder_name,
customer_id: "",
merchant_id: "",
bin: paymentRes?.data?.payment?.card_details?.card?.bin,
card_type: paymentRes?.data?.payment?.card_details?.card?.card_type,
agentId: agentId ? agentId : 0,
buyerId: buyerId ? buyerId : 0,
created_at: new Date()
};
/* Insert Card */
await axios.post(`${process.env.API_URL}/card`, cardData);
/* Payment history Data */
const paymentsData = {
payment_id: paymentRes?.data?.payment?.id,
amount: paymentRes?.data?.payment?.amount_money?.amount,
currency: paymentRes?.data?.payment?.amount_money?.currency,
status: paymentRes?.data?.payment?.status,
delay_duration: paymentRes?.data?.payment?.delay_duration,
source_type: paymentRes?.data?.payment?.source_type,
card_bin: paymentRes?.data?.payment?.card_details?.card?.bin,
order_id: paymentRes?.data?.payment?.order_id,
customer_id: paymentRes?.data?.payment?.receipt_number,
receipt_url: paymentRes?.data?.payment?.receipt_url,
version_token: paymentRes?.data?.payment?.version_token,
application_id: paymentRes?.data?.payment?.application_details?.application_id,
subscription_type: subscription_type,
agentId: agentId ? agentId : 0,
buyerId: buyerId ? buyerId : 0,
created_at: new Date()
};
/* Insert payements history */
await axios.post(`${process.env.API_URL}/payments`, paymentsData);
return paymentRes?.data;
}
}
} catch (error) {
console.log("ERROR--", error);
}
}
async updateCustomerPaymentService(cardholder_name, nonce, amount, agentId, buyerId, subscription_type) {
try {
const idempotency_key = crypto.randomBytes(22).toString("hex");
const customerRes = await axios.post(
`${process.env.SQUARE_URL}/v2/customers`,
{
email_address: process.env.SQUARE_EMAIL
},
this.headers
);
if (customerRes?.data) {
/* Make Payments */
await axios
.post(
`${process.env.SQUARE_URL}/v2/payments`,
{
idempotency_key: idempotency_key,
amount_money: {
amount: parseInt(amount),
currency: "USD"
},
source_id: "cnon:CBASEDacZZ-_R8qD5eLtl1LjCx0",
location_id: process.env.LOCATION_ID,
autocomplete: true
},
this.headers
)
.then((respo) => {
console.log("respo---", respo);
})
.catch((error) => {
console.log("Nonce error---", JSON.stringify(error));
});
return;
}
} catch (error) {
console.log("ERROR--", error);
}
}
async createCustomerPaymentSubscription(cardNonce, selectedPlan, agentId, amount) {
try {
const idempotency_key = crypto.randomBytes(22).toString("hex");
const customerRes = await axios.post(
`${process.env.SQUARE_URL}/v2/customers`,
{
email_address: process.env.SQUARE_EMAIL
},
this.headers
);
const customerId: string = customerRes?.data?.customer?.id;
const squareClient = new Client({
environment: Environment.Production, // Change to square.Environment.Production for testing for prod Production square.Environment.Production
accessToken: process.env.SQUARE_ACCESS_TOKEN,
squareVersion: process.env.SQUARE_API_VERSION
});
// get selected plan
const plan = await this.getListSubscriptionPlan();
// console.log('planplan', plan);
const activePlan = plan?.find((item) => ((item?.subscription_plan_data?.name === selectedPlan) && item?.present_at_all_locations));
console.log('Subscription Plan', JSON.stringify(
activePlan?.subscription_plan_data?.subscription_plan_variations?.[0]?.subscription_plan_variation_data?.phases?.[0]?.pricing?.price_money?.amount));
// console.log('Plan name', JSON.stringify(activePlan));
const createCardData = {
idempotencyKey:idempotency_key,
sourceId: cardNonce,
card:{
customerId: customerId
}
}
// Create a customer card to charge
const cardResult: any = await squareClient.cardsApi.createCard(createCardData);
// console.log('cardResult--', cardResult);
const cardId = cardResult?.result?.card?.id;
// get exiting subscription
const existSubscription = await this.paymentSubscriptionService.getSubscription(agentId);
let currDate: any = new Date();
currDate = moment(currDate, "YYYY-MM-DD").format("YYYY-MM-DD");
const existPlanCanceledDate = moment(existSubscription.canceledDate, "YYYY-MM-DD").format("YYYY-MM-DD");
let subscriptionStartDate = moment().format("YYYY-MM-DD");
let count = 0;
if (activePlan?.subscription_plan_data?.subscription_plan_variations?.[0]?.subscription_plan_variation_data?.phases?.[0]?.pricing?.price_money?.amount <= existSubscription?.price && existPlanCanceledDate > currDate) {
count = Math.abs(moment(currDate, "YYYY-MM-DD").startOf("day").diff(moment(existPlanCanceledDate, "YYYY-MM-DD").startOf("day"), "days")) + 1;
}
if (count > 0) {
subscriptionStartDate = moment(subscriptionStartDate).add(count, "days").format("YYYY-MM-DD");
}
const subscription: any = {
idempotencyKey: idempotency_key,
locationId: process.env.LOCATION_ID,
customerId: customerId,
planVariationId: activePlan?.subscription_plan_data?.subscription_plan_variations?.[0]?.id ?? "planId",
cardId: cardId,
startDate: subscriptionStartDate,
timezone: "America/Los_Angeles",
source: {
name: "Navihome"
}
};
//cancel exist Subscription
if (existSubscription?.subscriptionId && !existSubscription?.subscriptionId.includes("free")) {
const { result } = await squareClient.subscriptionsApi.cancelSubscription(existSubscription.subscriptionId);
}
// Create the subscription
const { result }: any = await squareClient.subscriptionsApi.createSubscription(subscription);
// console.log('resultresult', result);
const subscriptionData = {
agentId: agentId,
subscriptionId: result?.subscription?.id,
planId: result?.subscription?.planId,
status: count > 0 ? "PENDING" : result?.subscription?.status,
startDate: result?.subscription?.startDate,
canceledDate: moment(result?.subscription?.startDate).add(30, "days").format("YYYY-MM-DD"),
price: activePlan?.subscription_plan_data?.subscription_plan_variations?.[0]?.subscription_plan_variation_data?.phases?.[0]?.pricing?.price_money?.amount,
planName: activePlan?.subscription_plan_data?.name,
activePlan: count > 0 ? existSubscription?.planName : activePlan?.subscription_plan_data?.name
};
await this.paymentSubscriptionService.insertSubsciption(subscriptionData);
return JSON.parse(JSON.stringify(result.subscription, (key, value) => (typeof value === "bigint" ? value.toString() : value)));
} catch (error) {
console.log("ERROR--", error?.errors?.[0]);
return {
error: true,
message: "Payment Failed",
category: error?.errors?.[0]?.category,
code: error?.errors?.[0]?.code,
detail: error?.errors?.[0]?.detail //'This request could not be authorized.'
}
}
}
async createSubscriptionPlan() {
try {
const idempotency_key = crypto.randomBytes(22).toString("hex");
// create Plan
const newPlan = {
idempotency_key: idempotency_key,
object: {
type: "SUBSCRIPTION_PLAN",
id: "#basicPlan",
subscription_plan_data: {
name: "Navihome Basic Plan",
phases: [
{
cadence: "MONTHLY",
recurring_price_money: {
amount: 2999,
currency: "USD"
}
}
]
}
}
};
await axios
.post(`${process.env.SQUARE_URL}/v2/catalog/object`, newPlan, this.headers)
.then((respo) => {
console.log("respo---", respo);
return respo;
})
.catch((error) => {
console.log("error---", error);
return error;
});
} catch (err) {
console.log(err);
return err;
}
}
async getListSubscriptionPlan() {
try {
let planResult = [];
await axios
.get(`${process.env.SQUARE_URL}/v2/catalog/list`, this.headers)
.then((respo) => {
planResult = respo.data.objects;
})
.catch((error) => {
console.log("error---", error);
return error;
});
// const squareClient = new Client({
// environment: Environment.Production, // Change to square.Environment.Production for testing for prod Production
// accessToken: process.env.SQUARE_ACCESS_TOKEN,
// squareVersion: process.env.SQUARE_API_VERSION
// });
// const planResult: any = await squareClient.catalogApi.listCatalog();
// return JSON.parse(
// JSON.stringify(
// planResult.result.objects,
// (key, value) => (typeof value === "bigint" ? value.toString() : value) // return everything else unchanged
// )
// );
return planResult.filter(obj => obj.subscription_plan_data);
} catch (err) {
console.log(err);
return err;
}
}
async pauseSubscriptionPlan(agentId: number) {
try {
const squareClient = new Client({
environment: Environment.Production, // Change to square.Environment.Production for testing for prod Production
accessToken: process.env.SQUARE_ACCESS_TOKEN,
squareVersion: process.env.SQUARE_API_VERSION
});
const existSubscription = await this.paymentSubscriptionService.getSubscription(agentId);
const body = {
pauseEffectiveDate: moment().format("YYYY-MM-DD"),
pauseReason: "User want to pause account . Might be he can enable after some time."
};
if (existSubscription?.subscriptionId) {
const { result } = await squareClient.subscriptionsApi.pauseSubscription(existSubscription.subscriptionId, body);
return JSON.parse(
JSON.stringify(
result.subscription,
(key, value) => (typeof value === "bigint" ? value.toString() : value) // return everything else unchanged
)
);
}
} catch (err) {
console.log(err);
return err;
}
}
async deleteSubscriptionPlan(agentId: number) {
try {
const squareClient = new Client({
environment: Environment.Production, // Change to square.Environment.Production for testing for prod Production
accessToken: process.env.SQUARE_ACCESS_TOKEN,
squareVersion: process.env.SQUARE_API_VERSION
});
const existSubscription = await this.paymentSubscriptionService.getSubscription(agentId);
const { result } = await squareClient.subscriptionsApi.cancelSubscription(existSubscription.subscriptionId);
if (result?.actions?.[0]?.id) {
const response = await squareClient.subscriptionsApi.deleteSubscriptionAction(existSubscription.subscriptionId, result?.actions?.[0]?.id);
return response;
}
} catch (err) {
console.log(err);
return err;
}
}
async resumeSubscriptionPlan(agentId: number) {
try {
const squareClient = new Client({
environment: Environment.Production, // Change to square.Environment.Production for testing for prod Production
accessToken: process.env.SQUARE_ACCESS_TOKEN,
squareVersion: process.env.SQUARE_API_VERSION
});
const existSubscription = await this.paymentSubscriptionService.getSubscription(agentId);
const body = {
resumeEffectiveDate: moment().format("YYYY-MM-DD")
};
if (existSubscription?.subscriptionId) {
const response = await squareClient.subscriptionsApi.resumeSubscription(existSubscription.subscriptionId, body);
return response;
}
} catch (err) {
console.log(err);
return err;
}
}
async activatepaidToFreePlan(agentId: any, selectedPlan: any) {
const deleleResponse = await this.deleteSubscriptionPlan(agentId);
// get selected plan
const plan = await this.getListSubscriptionPlan();
const activePlan = plan.find((item) => item?.subscription_plan_data?.name === selectedPlan && item.present_at_all_locations);
const existSubscription = await this.paymentSubscriptionService.getSubscription(agentId);
const date = moment().format("YYYY-MM-DD");
const subscriptionData = {
agentId: agentId,
subscriptionId: `free-${"2324344-rerdf-43434"}-sub-${moment().format("YYYY-MM-DD")}-id`,
planId: `free-${"223232-fdsfdsf-33443"}-plan-${moment().format("YYYY-MM-DD")}-id`,
status: "ACTIVE",
startDate: new Date(),
canceledDate: date,
price: 0,
planName: "Navihome Free Plan",
activePlan: activePlan?.subscription_plan_data?.subscription_plan_variations?.[0]?.subscription_plan_variation_data?.phases?.[0]?.pricing?.price_money?.amount > existSubscription?.price ? existSubscription?.planName : activePlan?.subscription_plan_data?.name ?? "Navihome Free Plan"
};
const response = await this.paymentSubscriptionService.insertSubsciption(subscriptionData);
return response
}
}