@gorgo/medusa-payment-robokassa
Version:
Robokassa payment provider for Medusa
327 lines • 26.7 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("@medusajs/framework/utils");
const types_1 = require("../types");
const axios_1 = __importDefault(require("axios"));
const fast_xml_parser_1 = require("fast-xml-parser");
const utils_2 = require("../utils");
const crypto_1 = require("crypto");
class RobokassaBase extends utils_1.AbstractPaymentProvider {
static validateOptions(options) {
if (!(0, utils_1.isDefined)(options.merchantLogin)) {
throw new Error("Required option `merchantLogin` is missing in Robokassa provider");
}
if (!(0, utils_1.isDefined)(options.password1)) {
throw new Error("Required option `password1` is missing in Robokassa provider");
}
if (!(0, utils_1.isDefined)(options.password2)) {
throw new Error("Required option `password2` is missing in Robokassa provider");
}
if (!(0, utils_1.isDefined)(options.hashAlgorithm) || !types_1.HashAlgorithms.includes(options.hashAlgorithm)) {
throw new Error("Required option `hashAlgorithm` is missing in Robokassa provider");
}
}
constructor(container, options) {
super(container, options);
this.baseUrl_ = "https://auth.robokassa.ru";
this.paymentUrl_ = `${this.baseUrl_}/Merchant/Index.aspx`;
this.getPaymentUrl_ = `${this.baseUrl_}/Merchant/WebService/Service.asmx/OpStateExt`;
this.capturePaymentUrl_ = `${this.baseUrl_}/Merchant/Payment/Confirm`;
this.options_ = options;
this.logger_ = container.logger;
}
createSignature(signatureParams) {
const concatenatedParams = signatureParams.filter(v => v).join(":");
const res = (0, crypto_1.createHash)(this.options_.hashAlgorithm).update(concatenatedParams).digest('hex');
return res;
}
normalizePaymentParameters(extra) {
const res = {};
if (extra?.data?.SuccessUrl2)
res.SuccessUrl2 = extra?.data?.SuccessUrl2;
if (extra?.data?.SuccessUrl2Method)
res.SuccessUrl2Method = extra?.data?.SuccessUrl2Method;
if (extra?.data?.FailUrl2)
res.FailUrl2 = extra?.data?.FailUrl2;
if (extra?.data?.FailUrl2Method)
res.FailUrl2Method = extra?.data?.FailUrl2Method;
if (extra?.data?.EMail)
res.EMail = extra?.data?.EMail;
if (extra?.data?.Culture)
res.Culture = extra?.data?.Culture;
if (extra?.data?.isTest)
res.isTest =
(extra?.data?.isTest ??
this.options_.isTest) ? "1" : undefined;
if (extra?.data?.StepByStep)
res.StepByStep =
(extra?.data?.StepByStep ??
this.options_.capture) ? undefined : "true";
return res;
}
/**
* Initiate a new payment.
*/
async initiatePayment(input) {
this.logger_.debug(`RobokassaBase.initiatePayment input:\n${JSON.stringify(input, null, 2)}`);
const { amount, context = {} } = input;
const outSum = Number(amount).toFixed(2);
// TODO: can we avoide generating invoice id?
const invoiceId = (0, utils_2.stringToNumberHash)(context.idempotency_key).toString();
const sessionId = input.data?.session_id;
const additionalParameters = this.normalizePaymentParameters(input);
const raw = [
this.options_.merchantLogin,
outSum,
invoiceId,
additionalParameters.StepByStep,
additionalParameters.SuccessUrl2,
additionalParameters.SuccessUrl2Method,
additionalParameters.FailUrl2,
additionalParameters.FailUrl2Method,
this.options_.isTest ? this.options_.testPassword1 : this.options_.password1,
`Shp_SessionID=${sessionId}`
];
const signature = (0, utils_2.createSignature)(raw, this.options_.hashAlgorithm);
const payment = {
MerchantLogin: this.options_.merchantLogin,
OutSum: outSum,
InvoiceID: invoiceId,
SignatureValue: signature,
Shp_SessionID: sessionId,
...additionalParameters
};
const params = new URLSearchParams(payment).toString();
const paymentUrl = `${this.paymentUrl_}?${params}`;
return {
id: invoiceId,
data: {
paymentUrl: paymentUrl,
...payment
}
};
}
/**
* Capture an existing payment.
*/
async capturePayment(input) {
this.logger_.debug(`RobokassaBase.capturePayment input:\n${JSON.stringify(input, null, 2)}`);
const invoiceId = input.data?.InvoiceID;
const outSum = input.data?.OutSum;
const raw = [
this.options_.merchantLogin,
outSum,
invoiceId,
this.options_.isTest ? this.options_.testPassword1 : this.options_.password1
];
const signature = (0, utils_2.createSignature)(raw, this.options_.hashAlgorithm);
const capturePayment = {
MerchantLogin: this.options_.merchantLogin,
InvoiceID: invoiceId,
SignatureValue: signature,
OutSum: outSum
};
const params = new URLSearchParams(capturePayment).toString();
const capturePaymentUrl = `${this.capturePaymentUrl_}?${params}`;
try {
const response = await axios_1.default.post(capturePaymentUrl);
return { data: response.data };
}
catch (e) {
throw this.buildError("An error occurred in capturePayment", e);
}
}
/**
* Authorize a payment by retrieving its status.
*/
async authorizePayment(input) {
this.logger_.debug(`RobokassaBase.authorizePayment input:\n${JSON.stringify(input, null, 2)}`);
const statusResponse = await this.getPaymentStatus(input);
return statusResponse;
}
/**
* Delete a payment.
* Payment delete is not supported by Robokassa.
*/
async deletePayment(input) {
this.logger_.debug(`RobokassaBase.deletePayment input:\n${JSON.stringify(input, null, 2)}`);
return input;
}
/**
* Update a payment.
* Payment update is not supported by Robokassa.
*/
async updatePayment(input) {
this.logger_.debug(`RobokassaBase.updatePayment input:\n${JSON.stringify(input, null, 2)}`);
return input;
}
/**
* Refund a payment.
* Payment refund is not supported by Robokassa.
*/
async refundPayment(input) {
this.logger_.debug(`RobokassaBase.refundPayment input:\n${JSON.stringify(input, null, 2)}`);
return input;
}
/**
* Cancel an existing payment.
*/
async cancelPayment(input) {
this.logger_.debug(`RobokassaBase.cancelPayment input:\n${JSON.stringify(input, null, 2)}`);
return input;
}
/**
* Retrieve a payment.
*/
async retrievePayment(input) {
this.logger_.debug(`RobokassaBase.retrievePayment input:\n${JSON.stringify(input, null, 2)}`);
const invoiceId = input.data?.InvoiceID;
const raw = [
this.options_.merchantLogin,
invoiceId,
this.options_.isTest ? this.options_.testPassword2 : this.options_.password2
];
const signature = (0, utils_2.createSignature)(raw, this.options_.hashAlgorithm);
const params = new URLSearchParams({
MerchantLogin: this.options_.merchantLogin,
InvoiceID: invoiceId,
Signature: signature,
}).toString();
const url = `${this.getPaymentUrl_}?${params}`;
try {
const { data: xml } = await axios_1.default.post(url);
const parser = new fast_xml_parser_1.XMLParser({
ignoreAttributes: false,
attributeNamePrefix: "@_",
});
const parsed = parser.parse(xml);
const response = parsed['OperationStateResponse'];
return {
data: {
...input.data,
response: response
}
};
}
catch (e) {
throw this.buildError("An error occurred in retrievePayment", e);
}
}
/**
* Retrieve payment status and map it to Medusa status.
*/
async getPaymentStatus(input) {
this.logger_.debug(`RobokassaBase.getPaymentStatus input:\n${JSON.stringify(input, null, 2)}`);
try {
const response = (await this.retrievePayment(input)).data?.response;
if (!response || !response.Result || !response.State) {
throw new Error("Invalid response structure from Robokassa");
}
const result = response.Result;
const state = response.State;
const resultCode = parseInt(result.Code, 10);
const resultDescription = result.Description;
if (resultCode !== 0) {
throw new Error(`Robokassa error ${resultCode}: ${resultDescription}`);
}
const paymentState = parseInt(state.Code, 10);
switch (paymentState) {
case 10: // 10 is canceled
case 60: // 60 is refunded
return {
status: utils_1.PaymentSessionStatus.CANCELED,
// TODO: why we need input.data here?
data: {
...input.data,
response: response
}
};
case 20: // 20 is on hold (capture not done yet)
return {
status: utils_1.PaymentSessionStatus.AUTHORIZED,
data: {
...input.data,
response: response
}
};
case 5: // 5 is initiated
case 50: // 50 is payed, but still processing
return {
status: utils_1.PaymentSessionStatus.PENDING,
data: {
...input.data,
response: response
}
};
case 80: // 80 is paused
return {
status: utils_1.PaymentSessionStatus.REQUIRES_MORE,
data: {
...input.data,
response: response
}
};
case 100: // is successfully captured
return {
status: utils_1.PaymentSessionStatus.CAPTURED,
data: {
...input.data,
response: response
}
};
default:
return {
status: utils_1.PaymentSessionStatus.ERROR,
data: {
...input.data,
response: response
}
};
}
}
catch (e) {
throw this.buildError("An error occurred in getPaymentStatus", e);
}
}
async getWebhookActionAndData(payload) {
this.logger_.debug(`RobokassaBase.getWebhookActionAndData payload:\n${JSON.stringify(payload, null, 2)}`);
const data = payload.data;
const isValid = await this.isWebhookEventValid(data);
if (!isValid)
return {
action: utils_1.PaymentActions.NOT_SUPPORTED
};
const sessionId = data.Shp_SessionID;
const outSum = Number(data.OutSum);
return {
action: utils_1.PaymentActions.SUCCESSFUL,
data: { session_id: sessionId, amount: outSum }
};
}
async isWebhookEventValid(data) {
const incomingSignature = data.SignatureValue;
const raw = [
data.OutSum,
data.InvId,
this.options_.password2,
`Shp_SessionID=${data.Shp_SessionID}`
];
const signature = (0, utils_2.createSignature)(raw, this.options_.hashAlgorithm);
return signature === incomingSignature;
}
/**
* Helper to build errors with additional context.
*/
buildError(message, error) {
if (axios_1.default.isAxiosError(error)) {
return new Error(`${message}: ${error.response?.status} ${error.response?.data?.code} - ${error.response?.data?.description}`.trim());
}
return new Error(`${message}: ${error.message}`.trim());
}
}
RobokassaBase.identifier = "robokassa";
exports.default = RobokassaBase;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicm9ib2thc3NhLWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvcHJvdmlkZXJzL3BheW1lbnQtcm9ib2thc3NhL2NvcmUvcm9ib2thc3NhLWJhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxxREFLa0M7QUFhbEMsb0NBS2lCO0FBQ2pCLGtEQUF5QztBQUN6QyxxREFBMkM7QUFDM0Msb0NBR2lCO0FBQ2pCLG1DQUFtQztBQUVuQyxNQUFlLGFBQWMsU0FBUSwrQkFBeUM7SUFTNUUsTUFBTSxDQUFDLGVBQWUsQ0FBQyxPQUF5QjtRQUM5QyxJQUFJLENBQUMsSUFBQSxpQkFBUyxFQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDO1lBQ3RDLE1BQU0sSUFBSSxLQUFLLENBQUMsa0VBQWtFLENBQUMsQ0FBQTtRQUNyRixDQUFDO1FBQ0QsSUFBSSxDQUFDLElBQUEsaUJBQVMsRUFBQyxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztZQUNsQyxNQUFNLElBQUksS0FBSyxDQUFDLDhEQUE4RCxDQUFDLENBQUE7UUFDakYsQ0FBQztRQUNELElBQUksQ0FBQyxJQUFBLGlCQUFTLEVBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDbEMsTUFBTSxJQUFJLEtBQUssQ0FBQyw4REFBOEQsQ0FBQyxDQUFBO1FBQ2pGLENBQUM7UUFDRCxJQUFJLENBQUMsSUFBQSxpQkFBUyxFQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLHNCQUFjLENBQUMsUUFBUSxDQUFDLE9BQU8sQ0FBQyxhQUFnRCxDQUFDLEVBQUUsQ0FBQztZQUM1SCxNQUFNLElBQUksS0FBSyxDQUFDLGtFQUFrRSxDQUFDLENBQUE7UUFDckYsQ0FBQztJQUNILENBQUM7SUFFRCxZQUFZLFNBQTZCLEVBQUUsT0FBeUI7UUFDbEUsS0FBSyxDQUFDLFNBQVMsRUFBRSxPQUFPLENBQUMsQ0FBQTtR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