From 8dbaa5e4e297057f3a9c504262a62310fd42614c Mon Sep 17 00:00:00 2001 From: Ganesh Kumar <40178541+ganesh8056@users.noreply.github.com> Date: Thu, 4 Dec 2025 22:26:36 +0530 Subject: [PATCH] Feat: Authorise.net plugin (#14652) * Authorise net source code files * fix for the claude genereted code for the authorizenet * Removed repeted code * Resolved review Commits * Logo Changed * parsing and some review comments * fixed transaction key * Fixed Error Messages for config Page * chore: update version to 3.20.49-lts across all components --------- Co-authored-by: Pratush Co-authored-by: gsmithun4 --- .version | 2 +- frontend/.version | 2 +- marketplace/plugins/authorizenet/.gitignore | 5 + marketplace/plugins/authorizenet/README.md | 4 + .../plugins/authorizenet/__tests__/index.js | 7 + marketplace/plugins/authorizenet/lib/icon.svg | 6 + marketplace/plugins/authorizenet/lib/index.ts | 126 +++ .../plugins/authorizenet/lib/manifest.json | 64 ++ .../plugins/authorizenet/lib/operations.json | 238 +++++ .../authorizenet/lib/query_operations.ts | 839 ++++++++++++++++++ marketplace/plugins/authorizenet/lib/types.ts | 10 + marketplace/plugins/authorizenet/package.json | 27 + .../plugins/authorizenet/tsconfig.json | 11 + server/.version | 2 +- server/src/assets/marketplace/plugins.json | 11 + 15 files changed, 1351 insertions(+), 3 deletions(-) create mode 100644 marketplace/plugins/authorizenet/.gitignore create mode 100644 marketplace/plugins/authorizenet/README.md create mode 100644 marketplace/plugins/authorizenet/__tests__/index.js create mode 100644 marketplace/plugins/authorizenet/lib/icon.svg create mode 100644 marketplace/plugins/authorizenet/lib/index.ts create mode 100644 marketplace/plugins/authorizenet/lib/manifest.json create mode 100644 marketplace/plugins/authorizenet/lib/operations.json create mode 100644 marketplace/plugins/authorizenet/lib/query_operations.ts create mode 100644 marketplace/plugins/authorizenet/lib/types.ts create mode 100644 marketplace/plugins/authorizenet/package.json create mode 100644 marketplace/plugins/authorizenet/tsconfig.json diff --git a/.version b/.version index b1bc230b93..4023a07f73 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -3.20.48-lts +3.20.49-lts diff --git a/frontend/.version b/frontend/.version index b1bc230b93..4023a07f73 100644 --- a/frontend/.version +++ b/frontend/.version @@ -1 +1 @@ -3.20.48-lts +3.20.49-lts diff --git a/marketplace/plugins/authorizenet/.gitignore b/marketplace/plugins/authorizenet/.gitignore new file mode 100644 index 0000000000..23e6609462 --- /dev/null +++ b/marketplace/plugins/authorizenet/.gitignore @@ -0,0 +1,5 @@ +node_modules +lib/*.d.* +lib/*.js +lib/*.js.map +dist/* \ No newline at end of file diff --git a/marketplace/plugins/authorizenet/README.md b/marketplace/plugins/authorizenet/README.md new file mode 100644 index 0000000000..079272d987 --- /dev/null +++ b/marketplace/plugins/authorizenet/README.md @@ -0,0 +1,4 @@ + +# Authorize.Net + +Documentation on: https://docs.tooljet.com/docs/data-sources/authorizenet \ No newline at end of file diff --git a/marketplace/plugins/authorizenet/__tests__/index.js b/marketplace/plugins/authorizenet/__tests__/index.js new file mode 100644 index 0000000000..2b11716ca4 --- /dev/null +++ b/marketplace/plugins/authorizenet/__tests__/index.js @@ -0,0 +1,7 @@ +'use strict'; + +const authorizenet = require('../lib'); + +describe('authorizenet', () => { + it.todo('needs tests'); +}); diff --git a/marketplace/plugins/authorizenet/lib/icon.svg b/marketplace/plugins/authorizenet/lib/icon.svg new file mode 100644 index 0000000000..db3d64cf69 --- /dev/null +++ b/marketplace/plugins/authorizenet/lib/icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/marketplace/plugins/authorizenet/lib/index.ts b/marketplace/plugins/authorizenet/lib/index.ts new file mode 100644 index 0000000000..091014670f --- /dev/null +++ b/marketplace/plugins/authorizenet/lib/index.ts @@ -0,0 +1,126 @@ +import { QueryError, QueryResult, QueryService, ConnectionTestResult } from '@tooljet-marketplace/common'; +import { SourceOptions, QueryOptions } from './types'; +import ApiContracts from 'authorizenet/lib/apicontracts'; +import ApiControllers from 'authorizenet/lib/apicontrollers'; +import * as operations from './query_operations'; + +export default class Authorizenet implements QueryService { + + async testConnection(sourceOptions: SourceOptions): Promise { + try { + const merchantAuth = operations.getMerchantAuth(sourceOptions); + const getRequest = new ApiContracts.GetMerchantDetailsRequest(); + getRequest.setMerchantAuthentication(merchantAuth); + + const ctrl = new ApiControllers.GetMerchantDetailsController(getRequest.getJSON()); + ctrl.setEnvironment(operations.getEnvironment(sourceOptions.environment)); + return new Promise((resolve, reject) => { + ctrl.execute(() => { + const apiResponse = ctrl.getResponse(); + const response = new ApiContracts.GetMerchantDetailsResponse(apiResponse); + + if (response.getMessages().getResultCode() === ApiContracts.MessageTypeEnum.OK) { + resolve({ + status: 'ok', + }); + } else { + const errorMessage = response.getMessages().getMessage()[0].getText(); + reject( + new QueryError(errorMessage, errorMessage, { + code: response.getMessages().getMessage()[0].getCode(), + message: errorMessage, + }) + ); + } + }); + }); + } catch (error: any) { + throw new QueryError('Connection test failed', error.message, { + message: error.message, + name: error.name, + }); + } + } + + async run(sourceOptions: SourceOptions, queryOptions: QueryOptions, dataSourceId: string): Promise { + const { operation } = queryOptions; + + if (!operation) { + throw new QueryError('Invalid configuration', 'Operation is required', { + message: 'Operation parameter is missing', + }); + } + try { + let result: any; + + switch (operation) { + case 'charge_credit_card': + result = await operations.chargeCreditCard(sourceOptions, queryOptions); + break; + case 'authorize_credit_card': + result = await operations.authorizeCreditCard(sourceOptions, queryOptions); + break; + case 'capture_authorized_amount': + result = await operations.captureAuthorizedAmount(sourceOptions, queryOptions); + break; + case 'refund_transaction': + result = await operations.refundTransaction(sourceOptions, queryOptions); + break; + case 'void_transaction': + result = await operations.voidTransaction(sourceOptions, queryOptions); + break; + case 'charge_customer_profile': + result = await operations.chargeCustomerProfile(sourceOptions, queryOptions); + break; + case 'create_customer_pofile': + result = await operations.createCustomerProfile(sourceOptions,queryOptions); + break; + case 'get_customer_profile': + result = await operations.getCustomerProfile(sourceOptions,queryOptions); + break; + case 'get_customer_profileIds': + result = await operations.getCustomerProfileIds(sourceOptions,queryOptions); + break; + case 'update_customer_profile': + result = await operations.updateCustomerProfile(sourceOptions,queryOptions); + break; + case 'delete_customer_profile': + result = await operations.deleteCustomerProfile(sourceOptions,queryOptions); + break; + case 'create_customer_payment_profile': + result = await operations.createCustomerPaymentProfile(sourceOptions,queryOptions); + break; + case 'get_customer_payment_profile': + result = await operations.getCustomerPaymentProfile(sourceOptions,queryOptions); + break; + case 'validate_customer_payment_profile': + result = await operations.validateCustomerPaymentProfile(sourceOptions,queryOptions); + break; + case 'update_customer_payment_profile': + result = await operations.updateCustomerPaymentProfile(sourceOptions,queryOptions); + break; + case 'delete_customer_payment_profile': + result = await operations.deleteCustomerPaymentProfile(sourceOptions,queryOptions); + break; + case 'create_customer_profile_from_transaction': + result = await operations.createCustomerProfileFromTransaction(sourceOptions,queryOptions); + break; + default: + throw new QueryError('Invalid operation', `Operation '${operation}' is not supported`, { + operation, + }); + } + + return { + status: 'ok', + data: result, + }; + } catch (error: any) { + throw new QueryError('Operation failed', error.data.message, { + name : error.name, + code : error.data.code, + message : error.data.message + }); + } + } +} diff --git a/marketplace/plugins/authorizenet/lib/manifest.json b/marketplace/plugins/authorizenet/lib/manifest.json new file mode 100644 index 0000000000..aa271c92a5 --- /dev/null +++ b/marketplace/plugins/authorizenet/lib/manifest.json @@ -0,0 +1,64 @@ +{ + "$schema": "https://raw.githubusercontent.com/ToolJet/ToolJet/develop/plugins/schemas/manifest.schema.json", + "title": "Authorize.Net datasource", + "description": "A schema defining Authorize.Net datasource", + "type": "api", + "source": { + "name": "Authorize.Net", + "kind": "authorizenet", + "exposedVariables": { + "isLoading": false, + "data": {}, + "rawData": {} + }, + "options": { + "apiLoginId": { + "type": "string" + }, + "transactionKey": { + "type": "string", + "encrypted": true + }, + "environment": { + "type": "string" + } + } + }, + "defaults": { + "environment": { + "value": "sandbox" + } + }, + "properties": { + "apiLoginId": { + "label": "API login ID", + "key": "apiLoginId", + "type": "text", + "description": "Your Authorize.Net API login ID" + }, + "transactionKey": { + "label": "Transaction key", + "key": "transactionKey", + "type": "text", + "description": "Your Authorize.Net transaction key", + "encrypted": true + }, + "environment": { + "label": "Environment", + "key": "environment", + "type": "dropdown", + "description": "Select the API environment", + "list": [ + { + "label": "Sandbox [https://apitest.authorize.net]", + "value": "sandbox" + }, + { + "label": "Production [https://api.authorize.net]", + "value": "production" + } + ] + } + }, + "required": ["apiLoginId", "transactionKey"] +} \ No newline at end of file diff --git a/marketplace/plugins/authorizenet/lib/operations.json b/marketplace/plugins/authorizenet/lib/operations.json new file mode 100644 index 0000000000..0e1d3a8ad4 --- /dev/null +++ b/marketplace/plugins/authorizenet/lib/operations.json @@ -0,0 +1,238 @@ +{ + "$schema": "https://raw.githubusercontent.com/ToolJet/ToolJet/develop/plugins/schemas/operations.schema.json", + "title": "Authorize.Net datasource", + "description": "A schema defining Authorize.Net datasource", + "type": "api", + "defaults": { + "operation": "chargeCreditCard" + }, + "properties": { + "operation": { + "label": "Operation", + "key": "operation", + "type": "dropdown-component-flip", + "description": "Select an operation", + "list": [ + { "value": "charge_credit_card", "name": "Charge a Credit Card" }, + { "value": "authorize_credit_card", "name": "Authorize a Credit Card" }, + { "value": "capture_authorized_amount", "name": "Capture a Previously Authorized Amount" }, + { "value": "refund_transaction", "name": "Refund a Transaction" }, + { "value": "void_transaction", "name": "Void a Transaction" }, + { "value": "charge_customer_profile", "name": "Charge a Customer Profile" }, + { "value": "create_customer_pofile", "name": "Create a Customer Profile" }, + { "value": "get_customer_profile", "name": "Get Customer Profile" }, + { "value": "get_customer_profileIds", "name": "Get Customer Profile IDs" }, + { "value": "update_customer_profile", "name": "Update Customer Profile" }, + { "value": "delete_customer_profile", "name": "Delete Customer Profile" }, + { "value": "create_customer_payment_profile", "name": "Create Customer Payment Profile" }, + { "value": "get_customer_payment_profile", "name": "Get Customer Payment Profile" }, + { "value": "validate_customer_payment_profile", "name": "Validate Customer Payment Profile" }, + { "value": "update_customer_payment_profile", "name": "Update Customer Payment Profile" }, + { "value": "delete_customer_payment_profile", "name": "Delete Customer Payment Profile" }, + { "value": "create_customer_profile_from_transaction", "name": "Create Customer Profile from Transaction" } + ] + }, + "charge_credit_card": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for charging a credit card", + "placeholder": "{\n \"amount\": \"5.00\",\n \"cardNumber\": \"4111111111111111\",\n \"expirationDate\": \"2025-12\",\n \"cardCode\": \"123\",\n \"refId\": \"123456\",\n \"lineItems\": {\n \"lineItem\": [\n {\n \"itemId\": \"1\",\n \"name\": \"Product Name\",\n \"description\": \"Product Description\",\n \"quantity\": \"1\",\n \"unitPrice\": \"5.00\"\n }\n ]\n },\n \"tax\": {\n \"amount\": \"0.50\",\n \"name\": \"Sales Tax\",\n \"description\": \"State Tax\"\n },\n \"billTo\": {\n \"firstName\": \"John\",\n \"lastName\": \"Doe\",\n \"address\": \"123 Main St\",\n \"city\": \"Seattle\",\n \"state\": \"WA\",\n \"zip\": \"98101\",\n \"country\": \"US\"\n }\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Required: amount, cardNumber, expirationDate. Optional: cardCode (CVV), refId (max 20 chars), lineItems, tax, duty, shipping, poNumber, customer, billTo, shipTo, customerIP, transactionSettings, userFields, processingOptions, subsequentAuthInformation, authorizationIndicatorType. See Authorize.Net documentation for complete field specifications." + } + }, + "authorize_credit_card": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for authorizing a credit card", + "placeholder": "{\n \"amount\": \"5.00\",\n \"cardNumber\": \"4111111111111111\",\n \"expirationDate\": \"2025-12\",\n \"cardCode\": \"123\",\n \"refId\": \"123456\",\n \"lineItems\": {\n \"lineItem\": [\n {\n \"itemId\": \"1\",\n \"name\": \"Product Name\",\n \"description\": \"Product Description\",\n \"quantity\": \"1\",\n \"unitPrice\": \"5.00\"\n }\n ]\n },\n \"tax\": {\n \"amount\": \"0.50\",\n \"name\": \"Sales Tax\",\n \"description\": \"State Tax\"\n },\n \"billTo\": {\n \"firstName\": \"John\",\n \"lastName\": \"Doe\",\n \"address\": \"123 Main St\",\n \"city\": \"Seattle\",\n \"state\": \"WA\",\n \"zip\": \"98101\",\n \"country\": \"US\"\n }\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Required: amount, cardNumber, expirationDate. Optional: cardCode (CVV), refId (max 20 chars), lineItems, tax, duty, shipping, poNumber, customer, billTo, shipTo, customerIP, userFields, processingOptions, subsequentAuthInformation, authorizationIndicatorType. See Authorize.Net documentation for complete field specifications." + } + }, + "capture_authorized_amount": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for capturing a previously authorized amount", + "placeholder": "{\n \"refTransId\": \"1234567890\",\n \"amount\": \"5.00\",\n \"refId\": \"123456\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Required: refTransId (original authorization transaction ID), amount (must be <= authorized amount). Optional: refId (max 20 chars for reference tracking). See Authorize.Net documentation for complete request format." + } + }, + "refund_transaction": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for refunding a transaction", + "placeholder": "{\n \"transId\": \"80048625878\",\n \"amount\": \"1.00\",\n \"cardNumber\": \"0015\",\n \"expirationDate\": \"XXXX\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Provide the refund details as JSON. See Authorize.Net documentation for complete request format." + } + }, + "void_transaction": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for voiding a transaction", + "placeholder": "{\n \"transId\": \"12345678\",\n \"refId\": \"optional-ref-123\",\n \"terminalNumber\": \"optional-terminal\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Required: transId (transaction ID to void). Optional: refId (your reference ID, max 20 chars), terminalNumber (in-store terminal identifier)." + } + }, + "charge_customer_profile": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for charging a customer profile", + "placeholder": "{\n \"customerProfileId\": \"40338125\",\n \"customerPaymentProfileId\": \"1000177237\",\n \"amount\": \"45.00\",\n \"refId\": \"123456\",\n \"lineItems\": {\n \"lineItem\": [\n {\n \"itemId\": \"1\",\n \"name\": \"vase\",\n \"description\": \"Cannes logo\",\n \"quantity\": \"18\",\n \"unitPrice\": \"45.00\"\n }\n ]\n }\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Required: customerProfileId, customerPaymentProfileId (or use nested profile structure), amount. Optional: refId (max 20 chars), lineItems, tax, duty, shipping, poNumber, customer, billTo, shipTo, customerIP, processingOptions, subsequentAuthInformation, authorizationIndicatorType. See Authorize.Net documentation for complete request format." + } + }, + "create_customer_pofile": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for creating a customer profile", + "placeholder": "{\n \"email\": \"customer@example.com\",\n \"description\": \"Customer Name\",\n \"merchantCustomerId\": \"12345\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Provide the customer profile details as JSON. See Authorize.Net documentation for complete request format." + } + }, + "get_customer_profile": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for getting a customer profile", + "placeholder": "{\n \"customerProfileId\": \"123456\",\n \"refId\": \"ref123\",\n \"includeIssuerInfo\": true\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Provide customer profile retrieval parameters as JSON.\n\nParameters:\n• customerProfileId (required): Payment gateway-assigned ID\n• refId (optional): Merchant reference ID (up to 20 chars)\n• merchantCustomerId (optional): Merchant customer ID (up to 20 chars)\n• email (optional): Customer email (up to 255 chars)\n• unmaskExpirationDate (optional): Return unmasked expiration date (boolean)\n• includeIssuerInfo (optional): Include issuer number (IIN) in response (boolean)\n\nSee Authorize.Net documentation for complete details." + } + }, + "get_customer_profileIds": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for getting customer profile IDs (optional)", + "placeholder": "{}", + "height": "300px", + "mandatory": false, + "tooltip": "Optionally provide parameters as JSON. See Authorize.Net documentation for complete request format." + } + }, + "update_customer_profile": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for updating a customer profile", + "placeholder": "{\n \"customerProfileId\": \"123456\",\n \"email\": \"newemail@example.com\",\n \"description\": \"Updated Name\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Provide the updated customer profile details as JSON. See Authorize.Net documentation for complete request format." + } + }, + "delete_customer_profile": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for deleting a customer profile", + "placeholder": "{\n \"customerProfileId\": \"123456\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Provide the customer profile ID as JSON. See Authorize.Net documentation for complete request format." + } + }, + "create_customer_payment_profile": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for creating a customer payment profile", + "placeholder": "{\n \"customerProfileId\": \"123456\",\n \"cardNumber\": \"4111111111111111\",\n \"expirationDate\": \"2025-12\",\n \"cardCode\": \"123\",\n \"billTo\": {\n \"firstName\": \"John\",\n \"lastName\": \"Doe\",\n \"address\": \"123 Main St\",\n \"city\": \"Bellevue\",\n \"state\": \"WA\",\n \"zip\": \"98004\",\n \"country\": \"US\",\n \"phoneNumber\": \"000-000-0000\"\n },\n \"defaultPaymentProfile\": false,\n \"validationMode\": \"liveMode\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Required: customerProfileId, cardNumber, expirationDate. Optional: cardCode, billTo (firstName, lastName, company, address, city, state, zip, country, phoneNumber, faxNumber), defaultPaymentProfile (boolean), validationMode ('liveMode' or 'testMode'), refId (max 20 chars). See Authorize.Net documentation for complete request format." + } + }, + "get_customer_payment_profile": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for getting a customer payment profile", + "placeholder": "{\n \"customerProfileId\": \"10000\",\n \"customerPaymentProfileId\": \"20000\",\n \"includeIssuerInfo\": \"true\",\n \"refId\": \"get-payment-001\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Required: customerProfileId, customerPaymentProfileId. Optional: includeIssuerInfo (string 'true' or 'false' to include issuer information in response), refId (max 20 chars for reference tracking). See Authorize.Net documentation for complete request format." } + }, + "validate_customer_payment_profile": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for validating a customer payment profile", + "placeholder": "{\n \"customerProfileId\": \"123456\",\n \"customerPaymentProfileId\": \"234567\",\n \"validationMode\": \"testMode\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Provide the validation details as JSON. See Authorize.Net documentation for complete request format." + } + }, + "update_customer_payment_profile": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for updating a customer payment profile", + "placeholder": "{\n \"customerProfileId\": \"10000\",\n \"customerPaymentProfileId\": \"20000\",\n \"cardNumber\": \"4111111111111111\",\n \"expirationDate\": \"2026-01\",\n \"billTo\": {\n \"firstName\": \"John\",\n \"lastName\": \"Doe\",\n \"address\": \"123 Main St.\",\n \"city\": \"Bellevue\",\n \"state\": \"WA\",\n \"zip\": \"98004\",\n \"country\": \"US\",\n \"phoneNumber\": \"000-000-0000\"\n },\n \"defaultPaymentProfile\": false,\n \"validationMode\": \"liveMode\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Required: customerProfileId, customerPaymentProfileId, cardNumber, expirationDate. Optional: cardCode, billTo (firstName, lastName, company, address, city, state, zip, country, phoneNumber, faxNumber), defaultPaymentProfile (boolean), validationMode ('liveMode' or 'testMode'), refId (max 20 chars). See Authorize.Net documentation for complete request format." + } + }, + "delete_customer_payment_profile": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for deleting a customer payment profile", + "placeholder": "{\n \"customerProfileId\": \"123456\",\n \"customerPaymentProfileId\": \"234567\",\n \"refId\": \"delete-payment-001\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Required: customerProfileId (customer profile ID), customerPaymentProfileId (payment profile ID to delete). Optional: refId (max 20 chars for reference tracking). See Authorize.Net documentation for complete request format." + } + }, + "create_customer_profile_from_transaction": { + "requestBody": { + "label": "Request body", + "key": "requestBody", + "type": "codehinter", + "description": "JSON request body for creating a customer profile from a transaction", + "placeholder": "{\n \"transId\": \"1234567890\",\n \"customer\": {\n \"merchantCustomerId\": \"CUST123\",\n \"description\": \"Customer description\",\n \"email\": \"customer@example.com\"\n },\n \"profileType\": \"regular\",\n \"refId\": \"create-profile-001\"\n}", + "height": "300px", + "mandatory": true, + "tooltip": "Required: transId (transaction ID from successful transaction). At least one of the following must be provided in customer object: merchantCustomerId (max 20 chars), description (max 255 chars), or email (max 255 chars). Optional: profileType ('guest' or 'regular', defaults to 'regular'), refId (max 20 chars). See Authorize.Net documentation for complete request format." } + } + } +} \ No newline at end of file diff --git a/marketplace/plugins/authorizenet/lib/query_operations.ts b/marketplace/plugins/authorizenet/lib/query_operations.ts new file mode 100644 index 0000000000..6d2f59c659 --- /dev/null +++ b/marketplace/plugins/authorizenet/lib/query_operations.ts @@ -0,0 +1,839 @@ +import { QueryError, QueryResult, QueryService, ConnectionTestResult } from '@tooljet-marketplace/common'; +import { SourceOptions, QueryOptions } from './types'; +import ApiContracts from 'authorizenet/lib/apicontracts'; +import ApiControllers from 'authorizenet/lib/apicontrollers'; +import Constants from 'authorizenet/lib/constants'; + + +export function getEnvironment(env: string) { + const endpoints = Constants.constants?.endpoint; + if (!endpoints) { + throw new Error("Authorize.net endpoints not found in Constants"); + } + return env === "production" + ? endpoints.production + : endpoints.sandbox; +} + + export function getMerchantAuth(sourceOptions: SourceOptions): any { + const merchantAuthenticationType = new ApiContracts.MerchantAuthenticationType(); + merchantAuthenticationType.setName(sourceOptions.apiLoginId); + merchantAuthenticationType.setTransactionKey(sourceOptions.transactionKey); + return merchantAuthenticationType; + } +// helpers +function parseRequestBody(queryOptions: any): any { + try { + return typeof queryOptions.requestBody === 'string' + ? JSON.parse(queryOptions.requestBody) + : queryOptions.requestBody; + } catch (error) { + throw new QueryError( + 'Request parsing failed', + 'Invalid JSON format in request body', + { + code: 'INVALID_JSON', + message: error instanceof Error ? error.message : 'Failed to parse request body', + } + ); + } +} +function createCustomerAddress(addressData: any): any { + if (!addressData) return null; + + const address = new ApiContracts.CustomerAddressType(); + + if (addressData.firstName) address.setFirstName(addressData.firstName); + if (addressData.lastName) address.setLastName(addressData.lastName); + if (addressData.company) address.setCompany(addressData.company); + if (addressData.address) address.setAddress(addressData.address); + if (addressData.city) address.setCity(addressData.city); + if (addressData.state) address.setState(addressData.state); + if (addressData.zip) address.setZip(addressData.zip); + if (addressData.country) address.setCountry(addressData.country); + if (addressData.phoneNumber) address.setPhoneNumber(addressData.phoneNumber); + if (addressData.faxNumber) address.setFaxNumber(addressData.faxNumber); + + return address; +} +function createExtendedAmountType(data: any): any { + if (!data) return null; + + const extendedAmount = new ApiContracts.ExtendedAmountType(); + + if (data.amount) extendedAmount.setAmount(data.amount); + if (data.name) extendedAmount.setName(data.name); + if (data.description) extendedAmount.setDescription(data.description); + + return extendedAmount; +} +function setLineItemsIfExists(transactionRequest: any, lineItemsData: any): void { + if (!lineItemsData) return; + + const lineItemsArray = Array.isArray(lineItemsData.lineItem) + ? lineItemsData.lineItem + : [lineItemsData.lineItem]; + + const lineItems = []; + lineItemsArray.forEach(item => { + if (item) { + const lineItem = new ApiContracts.LineItemType(); + if (item.itemId) lineItem.setItemId(item.itemId); + if (item.name) lineItem.setName(item.name); + if (item.description) lineItem.setDescription(item.description); + if (item.quantity) lineItem.setQuantity(item.quantity); + if (item.unitPrice) lineItem.setUnitPrice(item.unitPrice); + lineItems.push(lineItem); + } + }); + + if (lineItems.length > 0) { + const lineItemsList = new ApiContracts.ArrayOfLineItem(); + lineItemsList.setLineItem(lineItems); + transactionRequest.setLineItems(lineItemsList); + } +} +function setTransactionAmounts(transactionRequest: any, params: any): void { + const tax = createExtendedAmountType(params.tax); + if (tax) { + transactionRequest.setTax(tax); + } + + const duty = createExtendedAmountType(params.duty); + if (duty) { + transactionRequest.setDuty(duty); + } + + const shipping = createExtendedAmountType(params.shipping); + if (shipping) { + transactionRequest.setShipping(shipping); + } +} +function setTransactionAddresses(transactionRequest: any, params: any): void { + const billTo = createCustomerAddress(params.billTo); + if (billTo) { + transactionRequest.setBillTo(billTo); + } + + const shipTo = createCustomerAddress(params.shipTo); + if (shipTo) { + transactionRequest.setShipTo(shipTo); + } +} +function createCreditCard(cardData: any): any { + if (!cardData) return null; + + const creditCard = new ApiContracts.CreditCardType(); + creditCard.setCardNumber(cardData.cardNumber); + creditCard.setExpirationDate(cardData.expirationDate); + if (cardData.cardCode) { + creditCard.setCardCode(cardData.cardCode); + } + + return creditCard; +} +function executeController(ctrl: any, ResponseClass: any, errorTitle: string,timeoutMs: number = 30000 ): Promise { + return new Promise((resolve, reject) => { + let isResolved = false; + const timeoutId = setTimeout(() => { + if (!isResolved) { + isResolved = true; + reject(new QueryError(errorTitle,`Request timed out after ${timeoutMs}ms`,{code: 'TIMEOUT_ERROR',message: `Request timed out after ${timeoutMs}ms`,}));} + }, timeoutMs); + ctrl.execute(() => { + clearTimeout(timeoutId); + if (isResolved) return; + isResolved = true; + + const apiResponse = ctrl.getResponse(); + const response = new ResponseClass(apiResponse); + + if (response.getMessages().getResultCode() === ApiContracts.MessageTypeEnum.OK) { + resolve(response); + } else { + const messages = response.getMessages()?.getMessage(); + const errorMessage = messages?.[0]?.getText() ?? 'Unknown error'; + const errorCode = messages?.[0]?.getCode() ?? 'UNKNOWN_ERROR'; + reject(new QueryError(errorTitle, errorMessage, { + code: errorCode, + message: errorMessage, + })); + } + }); + }); +} +function setProcessingOptions(transactionRequest: any, params: any): void { + if (!params.processingOptions) return; + + const processingOptions = new ApiContracts.ProcessingOptions(); + if (params.processingOptions.isSubsequentAuth) { + processingOptions.setIsSubsequentAuth(params.processingOptions.isSubsequentAuth); + } + transactionRequest.setProcessingOptions(processingOptions); +} +function setSubsequentAuthInformation(transactionRequest: any, params: any): void { + if (!params.subsequentAuthInformation) return; + + const subsequentAuthInfo = new ApiContracts.SubsequentAuthInformation(); + if (params.subsequentAuthInformation.originalNetworkTransId) { + subsequentAuthInfo.setOriginalNetworkTransId(params.subsequentAuthInformation.originalNetworkTransId); + } + if (params.subsequentAuthInformation.originalAuthAmount) { + subsequentAuthInfo.setOriginalAuthAmount(params.subsequentAuthInformation.originalAuthAmount); + } + if (params.subsequentAuthInformation.reason) { + subsequentAuthInfo.setReason(params.subsequentAuthInformation.reason); + } + transactionRequest.setSubsequentAuthInformation(subsequentAuthInfo); +} +function setAuthorizationIndicatorType(transactionRequest: any, params: any): void { + if (!params.authorizationIndicatorType) return; + + const authIndicatorType = new ApiContracts.AuthorizationIndicatorType(); + if (params.authorizationIndicatorType.authorizationIndicator) { + authIndicatorType.setAuthorizationIndicator(params.authorizationIndicatorType.authorizationIndicator); + } + transactionRequest.setAuthorizationIndicatorType(authIndicatorType); +} +function setCustomerData(transactionRequest: any, params: any): void { + if (params.customer) { + const customer = new ApiContracts.CustomerDataType(); + if (params.customer.id) customer.setId(params.customer.id); + transactionRequest.setCustomer(customer); + } + + if (params.customerIP) { + transactionRequest.setCustomerIP(params.customerIP); + } +} +function setUserFields(transactionRequest: any, params: any): void { + if (!params.userFields) return; + + const userFieldsArray = Array.isArray(params.userFields.userField) + ? params.userFields.userField + : [params.userFields.userField]; + + const userFields = []; + userFieldsArray.forEach(uf => { + if (uf) { + const userField = new ApiContracts.UserField(); + if (uf.name) userField.setName(uf.name); + if (uf.value) userField.setValue(uf.value); + userFields.push(userField); + } + }); + + if (userFields.length > 0) { + const userFieldsList = new ApiContracts.TransactionRequestType.UserFields(); + userFieldsList.setUserField(userFields); + transactionRequest.setUserFields(userFieldsList); + } +} +function setTransactionSettings(transactionRequest: any, params: any): void { + if (!params.transactionSettings) return; + + const settingsList = new ApiContracts.ArrayOfSetting(); + const settingsArray = Array.isArray(params.transactionSettings.setting) + ? params.transactionSettings.setting + : [params.transactionSettings.setting]; + + settingsArray.forEach(s => { + const setting = new ApiContracts.SettingType(); + if (s.settingName) setting.setSettingName(s.settingName); + if (s.settingValue) setting.setSettingValue(s.settingValue); + settingsList.getSetting().push(setting); + }); + transactionRequest.setTransactionSettings(settingsList); +} +function validateAmount(amount: any, operationName: string): void { + if (!amount || amount <= 0) { + throw new QueryError( + `${operationName} failed`, + 'Amount must be a positive number', + { + code: 'INVALID_AMOUNT', + message: 'Amount must be greater than 0', + } + ); + } +} + +//main operations +export async function chargeCreditCard(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + + validateAmount(params.amount, 'Transaction'); + + const creditCard = createCreditCard(params); + + const paymentType = new ApiContracts.PaymentType(); + paymentType.setCreditCard(creditCard); + + const transactionRequestType = new ApiContracts.TransactionRequestType(); + transactionRequestType.setTransactionType(ApiContracts.TransactionTypeEnum.AUTHCAPTURETRANSACTION); + transactionRequestType.setPayment(paymentType); + transactionRequestType.setAmount(params.amount); + + setLineItemsIfExists(transactionRequestType, params.lineItems); + setTransactionAmounts(transactionRequestType, params); + setTransactionAddresses(transactionRequestType, params); + + if (params.poNumber) { + transactionRequestType.setPoNumber(params.poNumber); + } + + setCustomerData(transactionRequestType, params); + setTransactionSettings(transactionRequestType, params); + setUserFields(transactionRequestType, params); + setProcessingOptions(transactionRequestType, params); + setSubsequentAuthInformation(transactionRequestType, params); + setAuthorizationIndicatorType(transactionRequestType, params); + + const createRequest = new ApiContracts.CreateTransactionRequest(); + createRequest.setMerchantAuthentication(merchantAuth); + createRequest.setTransactionRequest(transactionRequestType); + createRequest.setRefId(params.refId); + + const ctrl = new ApiControllers.CreateTransactionController(createRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.CreateTransactionResponse,"Transaction failed"); +} + +export async function authorizeCreditCard(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + validateAmount(params.amount, 'Authorization'); + const cardData = params.payment?.creditCard || params; + const creditCard = createCreditCard(cardData); + + const paymentType = new ApiContracts.PaymentType(); + paymentType.setCreditCard(creditCard); + + const transactionRequestType = new ApiContracts.TransactionRequestType(); + transactionRequestType.setTransactionType(ApiContracts.TransactionTypeEnum.AUTHONLYTRANSACTION); + transactionRequestType.setPayment(paymentType); + transactionRequestType.setAmount(params.amount); + + setLineItemsIfExists(transactionRequestType, params.lineItems); + setTransactionAmounts(transactionRequestType, params); + setTransactionAddresses(transactionRequestType, params); + + if (params.poNumber) { + transactionRequestType.setPoNumber(params.poNumber); + } + + setCustomerData(transactionRequestType, params); + setUserFields(transactionRequestType, params); + setProcessingOptions(transactionRequestType, params); + setSubsequentAuthInformation(transactionRequestType, params); + setAuthorizationIndicatorType(transactionRequestType, params); + + const createRequest = new ApiContracts.CreateTransactionRequest(); + createRequest.setMerchantAuthentication(merchantAuth); + createRequest.setTransactionRequest(transactionRequestType); + if (params.refId) { + createRequest.setRefId(params.refId); + } + + const ctrl = new ApiControllers.CreateTransactionController(createRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.CreateTransactionResponse,"Authorization failed"); +} + +export async function captureAuthorizedAmount(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + validateAmount(params.amount, 'Capture'); + const transactionRequestType = new ApiContracts.TransactionRequestType(); + transactionRequestType.setTransactionType(ApiContracts.TransactionTypeEnum.PRIORAUTHCAPTURETRANSACTION); + transactionRequestType.setAmount(params.amount); + transactionRequestType.setRefTransId(params.refTransId); + + const createRequest = new ApiContracts.CreateTransactionRequest(); + createRequest.setMerchantAuthentication(merchantAuth); + createRequest.setTransactionRequest(transactionRequestType); + if (params.refId) { + createRequest.setRefId(params.refId); + } + + const ctrl = new ApiControllers.CreateTransactionController(createRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.CreateTransactionResponse,"Capture failed"); +} + +export async function refundTransaction(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + validateAmount(params.amount, 'Refund'); + const creditCard = new ApiContracts.CreditCardType(); + creditCard.setCardNumber(params.cardNumber); + creditCard.setExpirationDate(params.expirationDate); + const paymentType = new ApiContracts.PaymentType(); + paymentType.setCreditCard(creditCard); + + const transactionRequestType = new ApiContracts.TransactionRequestType(); + transactionRequestType.setTransactionType(ApiContracts.TransactionTypeEnum.REFUNDTRANSACTION); + transactionRequestType.setAmount(params.amount); + transactionRequestType.setPayment(paymentType); + transactionRequestType.setRefTransId(params.transId); + + const createRequest = new ApiContracts.CreateTransactionRequest(); + createRequest.setMerchantAuthentication(merchantAuth); + createRequest.setTransactionRequest(transactionRequestType); + + const ctrl = new ApiControllers.CreateTransactionController(createRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.CreateTransactionResponse,"Refund failed"); +} + +export async function voidTransaction(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + + if (!params.transId) { + throw new QueryError( + 'Void failed', + 'Missing required parameter: transId', + { + code: 'MISSING_PARAM', + message: 'transId is required for void transaction', + } + ); + } + + const transactionRequestType = new ApiContracts.TransactionRequestType(); + transactionRequestType.setTransactionType(ApiContracts.TransactionTypeEnum.VOIDTRANSACTION); + transactionRequestType.setRefTransId(params.transId); + + if (params.terminalNumber) { + transactionRequestType.setTerminalNumber(params.terminalNumber); + } + + const createRequest = new ApiContracts.CreateTransactionRequest(); + createRequest.setMerchantAuthentication(merchantAuth); + createRequest.setTransactionRequest(transactionRequestType); + + if (params.refId) { + const refId = params.refId.toString().substring(0, 20); + createRequest.setRefId(refId); + } + + const ctrl = new ApiControllers.CreateTransactionController(createRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + return executeController(ctrl,ApiContracts.CreateTransactionResponse,"Void failed"); +} + +export async function chargeCustomerProfile(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + validateAmount(params.amount, 'Charge customer profile'); + const profileData = params.profile || params; + + const profileToCharge = new ApiContracts.CustomerProfilePaymentType(); + profileToCharge.setCustomerProfileId( + profileData.customerProfileId || params.customerProfileId + ); + + const paymentProfile = new ApiContracts.PaymentProfile(); + paymentProfile.setPaymentProfileId( + profileData.paymentProfile?.paymentProfileId || params.customerPaymentProfileId + ); + profileToCharge.setPaymentProfile(paymentProfile); + + const transactionRequestType = new ApiContracts.TransactionRequestType(); + transactionRequestType.setTransactionType(ApiContracts.TransactionTypeEnum.AUTHCAPTURETRANSACTION); + transactionRequestType.setProfile(profileToCharge); + transactionRequestType.setAmount(params.amount); + + setLineItemsIfExists(transactionRequestType, params.lineItems); + setTransactionAmounts(transactionRequestType, params); + setTransactionAddresses(transactionRequestType, params); + + if (params.poNumber) { + transactionRequestType.setPoNumber(params.poNumber); + } + + setCustomerData(transactionRequestType, params); + setProcessingOptions(transactionRequestType, params); + setSubsequentAuthInformation(transactionRequestType, params); + setAuthorizationIndicatorType(transactionRequestType, params); + + const createRequest = new ApiContracts.CreateTransactionRequest(); + createRequest.setMerchantAuthentication(merchantAuth); + createRequest.setTransactionRequest(transactionRequestType); + + if (params.refId) { + createRequest.setRefId(params.refId); + } + + const ctrl = new ApiControllers.CreateTransactionController(createRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + return executeController(ctrl,ApiContracts.CreateTransactionResponse,"Charge customer profile failed"); +} + +export async function createCustomerProfile(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + + const customerProfile = new ApiContracts.CustomerProfileType(); + + if (params.merchantCustomerId) { + customerProfile.setMerchantCustomerId(params.merchantCustomerId); + } + if (params.description) { + customerProfile.setDescription(params.description); + } + if (params.email) { + customerProfile.setEmail(params.email); + } + + if (params.profileType) { + customerProfile.setProfileType(params.profileType); + } + + if (params.paymentProfiles && Array.isArray(params.paymentProfiles)) { + const paymentProfilesList = params.paymentProfiles.map((profile: any) => { + const paymentProfile = new ApiContracts.CustomerPaymentProfileType(); + + if (profile.customerType) { + paymentProfile.setCustomerType(profile.customerType); + } + + const billTo = createCustomerAddress(profile.billTo); + if (billTo) { + paymentProfile.setBillTo(billTo); + } + + if (profile.payment) { + const payment = new ApiContracts.PaymentType(); + + if (profile.payment.creditCard) { + const creditCard = createCreditCard(profile.payment.creditCard); + payment.setCreditCard(creditCard); + } + + if (profile.payment.bankAccount) { + const bankAccount = new ApiContracts.BankAccountType(); + bankAccount.setAccountType(profile.payment.bankAccount.accountType); + bankAccount.setRoutingNumber(profile.payment.bankAccount.routingNumber); + bankAccount.setAccountNumber(profile.payment.bankAccount.accountNumber); + bankAccount.setNameOnAccount(profile.payment.bankAccount.nameOnAccount); + if (profile.payment.bankAccount.echeckType) { + bankAccount.setEcheckType(profile.payment.bankAccount.echeckType); + } + if (profile.payment.bankAccount.bankName) { + bankAccount.setBankName(profile.payment.bankAccount.bankName); + } + payment.setBankAccount(bankAccount); + } + + if (profile.payment.opaqueData) { + const opaqueData = new ApiContracts.OpaqueDataType(); + opaqueData.setDataDescriptor(profile.payment.opaqueData.dataDescriptor); + opaqueData.setDataValue(profile.payment.opaqueData.dataValue); + payment.setOpaqueData(opaqueData); + } + + paymentProfile.setPayment(payment); + } + + return paymentProfile; + }); + + customerProfile.setPaymentProfiles(paymentProfilesList); + } + + if (params.shipToList && Array.isArray(params.shipToList)) { + const shipToList = params.shipToList.map((address: any) => createCustomerAddress(address)); + customerProfile.setShipToList(shipToList); + } + + const createRequest = new ApiContracts.CreateCustomerProfileRequest(); + createRequest.setMerchantAuthentication(merchantAuth); + createRequest.setProfile(customerProfile); + + if (params.refId) { + createRequest.setRefId(params.refId); + } + + if (params.validationMode) { + createRequest.setValidationMode(params.validationMode); + } + + const ctrl = new ApiControllers.CreateCustomerProfileController(createRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.CreateCustomerProfileResponse,"Create customer profile failed"); +} + +export async function getCustomerProfile(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + + const getRequest = new ApiContracts.GetCustomerProfileRequest(); + getRequest.setMerchantAuthentication(merchantAuth); + getRequest.setCustomerProfileId(params.customerProfileId); + + if (params.refId !== undefined && params.refId !== null) { + getRequest.setRefId(params.refId); + } + + if (params.merchantCustomerId !== undefined && params.merchantCustomerId !== null) { + getRequest.setMerchantCustomerId(params.merchantCustomerId); + } + + if (params.email !== undefined && params.email !== null) { + getRequest.setEmail(params.email); + } + + if (params.unmaskExpirationDate !== undefined) { + getRequest.setUnmaskExpirationDate( + params.unmaskExpirationDate === true || params.unmaskExpirationDate === "true" + ); + } + + if (params.includeIssuerInfo !== undefined) { + getRequest.setIncludeIssuerInfo( + params.includeIssuerInfo === true || params.includeIssuerInfo === "true" + ); + } + + const ctrl = new ApiControllers.GetCustomerProfileController(getRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.GetCustomerProfileResponse,"Get customer profile failed"); +} + +export async function getCustomerProfileIds(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + + const params = parseRequestBody(queryOptions); + + const getRequest = new ApiContracts.GetCustomerProfileIdsRequest(); + getRequest.setMerchantAuthentication(merchantAuth); + + const ctrl = new ApiControllers.GetCustomerProfileIdsController(getRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.GetCustomerProfileIdsResponse,"Get customer profile IDs failed"); +} + +export async function updateCustomerProfile(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + + const customerProfile = new ApiContracts.CustomerProfileExType(); + customerProfile.setCustomerProfileId(params.customerProfileId); + if (params.merchantCustomerId) { + customerProfile.setMerchantCustomerId(params.merchantCustomerId); + } + if (params.description) { + customerProfile.setDescription(params.description); + } + if (params.email) { + customerProfile.setEmail(params.email); + } + + const updateRequest = new ApiContracts.UpdateCustomerProfileRequest(); + updateRequest.setMerchantAuthentication(merchantAuth); + updateRequest.setProfile(customerProfile); + + const ctrl = new ApiControllers.UpdateCustomerProfileController(updateRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.UpdateCustomerProfileResponse,"Update customer profile failed"); +} + +export async function deleteCustomerProfile(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + + const deleteRequest = new ApiContracts.DeleteCustomerProfileRequest(); + deleteRequest.setMerchantAuthentication(merchantAuth); + deleteRequest.setCustomerProfileId(params.customerProfileId); + if (params.refId) { + deleteRequest.setRefId(params.refId); + } + + const ctrl = new ApiControllers.DeleteCustomerProfileController(deleteRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl, ApiContracts.DeleteCustomerProfileResponse,"Delete customer profile failed"); +} + +export async function createCustomerPaymentProfile(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + const cardData = params.payment?.creditCard || params; + const creditCard = createCreditCard(cardData); + + const paymentType = new ApiContracts.PaymentType(); + paymentType.setCreditCard(creditCard); + + const customerPaymentProfile = new ApiContracts.CustomerPaymentProfileType(); + customerPaymentProfile.setPayment(paymentType); + + const billTo = createCustomerAddress(params.billTo); + if (billTo) { + customerPaymentProfile.setBillTo(billTo); + } + + if (params.defaultPaymentProfile !== undefined) { + customerPaymentProfile.setDefaultPaymentProfile(params.defaultPaymentProfile); + } + + const createRequest = new ApiContracts.CreateCustomerPaymentProfileRequest(); + createRequest.setMerchantAuthentication(merchantAuth); + createRequest.setCustomerProfileId(params.customerProfileId); + createRequest.setPaymentProfile(customerPaymentProfile); + + if (params.validationMode) { + createRequest.setValidationMode(params.validationMode); + } + + if (params.refId) { + createRequest.setRefId(params.refId); + } + + const ctrl = new ApiControllers.CreateCustomerPaymentProfileController(createRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl, ApiContracts.CreateCustomerPaymentProfileResponse,"Create customer payment profile failed"); +} + +export async function getCustomerPaymentProfile(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + + const getRequest = new ApiContracts.GetCustomerPaymentProfileRequest(); + getRequest.setMerchantAuthentication(merchantAuth); + getRequest.setCustomerProfileId(params.customerProfileId); + getRequest.setCustomerPaymentProfileId(params.customerPaymentProfileId); + + const ctrl = new ApiControllers.GetCustomerPaymentProfileController(getRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.GetCustomerPaymentProfileResponse, "Get customer payment profile failed"); +} + +export async function validateCustomerPaymentProfile(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + + const validateRequest = new ApiContracts.ValidateCustomerPaymentProfileRequest(); + validateRequest.setMerchantAuthentication(merchantAuth); + validateRequest.setCustomerProfileId(params.customerProfileId); + validateRequest.setCustomerPaymentProfileId(params.customerPaymentProfileId); + validateRequest.setValidationMode( + params.validationMode === 'liveMode' + ? ApiContracts.ValidationModeEnum.LIVEMODE + : ApiContracts.ValidationModeEnum.TESTMODE + ); + + const ctrl = new ApiControllers.ValidateCustomerPaymentProfileController(validateRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.ValidateCustomerPaymentProfileResponse,"Validate customer payment profile failed"); +} + +export async function updateCustomerPaymentProfile(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + const profileData = params.paymentProfile || params; + const cardData = profileData.payment?.creditCard || profileData; + const creditCard = createCreditCard(cardData); + const paymentType = new ApiContracts.PaymentType(); + paymentType.setCreditCard(creditCard); + + const customerPaymentProfile = new ApiContracts.CustomerPaymentProfileExType(); + customerPaymentProfile.setPayment(paymentType); + customerPaymentProfile.setCustomerPaymentProfileId( + profileData.customerPaymentProfileId || params.customerPaymentProfileId + ); + + const billTo = createCustomerAddress(profileData.billTo); + if (billTo) { + customerPaymentProfile.setBillTo(billTo); + } + + if (profileData.defaultPaymentProfile !== undefined) { + customerPaymentProfile.setDefaultPaymentProfile(profileData.defaultPaymentProfile); + } + + const updateRequest = new ApiContracts.UpdateCustomerPaymentProfileRequest(); + updateRequest.setMerchantAuthentication(merchantAuth); + updateRequest.setCustomerProfileId(params.customerProfileId); + updateRequest.setPaymentProfile(customerPaymentProfile); + + if (params.validationMode) { + updateRequest.setValidationMode(params.validationMode); + } + + if (params.refId) { + updateRequest.setRefId(params.refId); + } + + const ctrl = new ApiControllers.UpdateCustomerPaymentProfileController(updateRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.UpdateCustomerPaymentProfileResponse,"Update customer payment profile failed"); +} + +export async function deleteCustomerPaymentProfile(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + + const deleteRequest = new ApiContracts.DeleteCustomerPaymentProfileRequest(); + deleteRequest.setMerchantAuthentication(merchantAuth); + deleteRequest.setCustomerProfileId(params.customerProfileId); + deleteRequest.setCustomerPaymentProfileId(params.customerPaymentProfileId); + + if (params.refId) { + deleteRequest.setRefId(params.refId); + } + const ctrl = new ApiControllers.DeleteCustomerPaymentProfileController(deleteRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.DeleteCustomerPaymentProfileResponse,"Delete customer payment profile failed"); +} + +export async function createCustomerProfileFromTransaction(sourceOptions: SourceOptions, queryOptions: any): Promise { + const merchantAuth = getMerchantAuth(sourceOptions); + const params = parseRequestBody(queryOptions); + + const createRequest = new ApiContracts.CreateCustomerProfileFromTransactionRequest(); + createRequest.setMerchantAuthentication(merchantAuth); + createRequest.setTransId(params.transId); + + if (params.customer) { + const customer = new ApiContracts.CustomerProfileBaseType(); + if (params.customer.merchantCustomerId) { + customer.setMerchantCustomerId(params.customer.merchantCustomerId); + } + if (params.customer.description) { + customer.setDescription(params.customer.description); + } + if (params.customer.email) { + customer.setEmail(params.customer.email); + } + createRequest.setCustomer(customer); + } + + if (params.profileType) { + createRequest.setProfileType(params.profileType); + } + + if (params.refId) { + createRequest.setRefId(params.refId); + } + + const ctrl = new ApiControllers.CreateCustomerProfileFromTransactionController(createRequest.getJSON()); + ctrl.setEnvironment(getEnvironment(sourceOptions.environment)); + + return executeController(ctrl,ApiContracts.CreateCustomerProfileResponse,"Create customer profile from transaction failed"); +} \ No newline at end of file diff --git a/marketplace/plugins/authorizenet/lib/types.ts b/marketplace/plugins/authorizenet/lib/types.ts new file mode 100644 index 0000000000..c651b3e705 --- /dev/null +++ b/marketplace/plugins/authorizenet/lib/types.ts @@ -0,0 +1,10 @@ +export type SourceOptions = { + apiLoginId: string; + transactionKey: string; + environment: 'sandbox' | 'production'; +}; + +export type QueryOptions = { + operation: string; + requestBody?: string; +}; diff --git a/marketplace/plugins/authorizenet/package.json b/marketplace/plugins/authorizenet/package.json new file mode 100644 index 0000000000..257b18fb9c --- /dev/null +++ b/marketplace/plugins/authorizenet/package.json @@ -0,0 +1,27 @@ +{ + "name": "@tooljet-marketplace/authorizenet", + "version": "1.0.0", + "main": "dist/index.js", + "types": "dist/index.d.ts", + "directories": { + "lib": "lib", + "test": "__tests__" + }, + "files": [ + "lib" + ], + "scripts": { + "test": "echo \"Error: run tests from root\" && exit 1", + "build": "ncc build lib/index.ts -o dist", + "watch": "ncc build lib/index.ts -o dist --watch" + }, + "homepage": "https://github.com/tooljet/tooljet#readme", + "dependencies": { + "@tooljet-marketplace/common": "^1.0.0", + "authorizenet": "^1.0.10" + }, + "devDependencies": { + "@vercel/ncc": "^0.34.0", + "typescript": "^4.7.4" + } +} diff --git a/marketplace/plugins/authorizenet/tsconfig.json b/marketplace/plugins/authorizenet/tsconfig.json new file mode 100644 index 0000000000..a18a801b14 --- /dev/null +++ b/marketplace/plugins/authorizenet/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "lib" + }, + "exclude": [ + "node_modules", + "dist" + ] +} \ No newline at end of file diff --git a/server/.version b/server/.version index b1bc230b93..4023a07f73 100644 --- a/server/.version +++ b/server/.version @@ -1 +1 @@ -3.20.48-lts +3.20.49-lts diff --git a/server/src/assets/marketplace/plugins.json b/server/src/assets/marketplace/plugins.json index b056280c6a..e2d6ad1740 100644 --- a/server/src/assets/marketplace/plugins.json +++ b/server/src/assets/marketplace/plugins.json @@ -320,5 +320,16 @@ "id": "fedex", "author": "Tooljet", "timestamp": "Fri, 05 Sep 2025 05:46:39 GMT" + }, + { + "name": "Authorize.Net", + "description": "Plugin for payment processing and customer profile management", + "version": "1.0.0", + "id": "authorizenet", + "author": "Tooljet", + "timestamp": "Tue, 25 Nov 2025 16:27:22 GMT", + "tags": [ + "Payment" + ] } ] \ No newline at end of file