Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/CI_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'

- name: Install dependencies
run: npm ci

- name: Run ESLint
run: npm run lint

Expand Down
69 changes: 69 additions & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Testing Guide

This guide describes how to test the `paytrail-js-sdk` locally, focusing on the recent changes to `createAddCardFormRequest`.

## Prerequisites

- Node.js (>= 20)
- npm

## Running Automated Tests

To run the unit tests, use the following command:

```bash
npm test
```

To run only the tests related to `createAddCardFormRequest`:

```bash
npm test -- tests/create-add-card-form.test.ts
```

## Manual / Integration Verification

### Setup

1. Ensure you have valid Paytrail Merchant credentials (Merchant ID and Secret Key).
2. The current test suite uses default test credentials (`merchantId: 695861`, `secret: MONISAIPPUAKAUPPIAS`).

### Test Flow

1. Instantiate `PaytrailClient` with your credentials.
2. Create an `AddCardFormRequest` object with only the business fields:
- `checkoutRedirectSuccessUrl`
- `checkoutRedirectCancelUrl`
- `language` (optional)
- `checkoutCallbackSuccessUrl` (optional)
- `checkoutCallbackCancelUrl` (optional)
3. Call `client.createAddCardFormRequest(request)`.
4. Inspect the result. It should contain a `redirectUrl`.

### Example Code

```typescript
import { PaytrailClient, AddCardFormRequest } from '@paytrail/paytrail-js-sdk'

const client = new PaytrailClient({
merchantId: 695861,
secretKey: 'MONISAIPPUAKAUPPIAS',
platformName: 'test'
})

const run = async () => {
const request = new AddCardFormRequest()
request.checkoutRedirectSuccessUrl = 'https://example.com/success'
request.checkoutRedirectCancelUrl = 'https://example.com/cancel'
request.language = 'EN'

try {
const response = await client.createAddCardFormRequest(request)
console.log('Redirect URL:', response.data.redirectUrl)
} catch (error) {
console.error('Error:', error)
}
}

run()
```
24 changes: 0 additions & 24 deletions dist/models/request/add-card-form.model.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,6 @@
*
*/
export declare class AddCardFormRequest {
/**
* Paytrail account ID.
*/
checkoutAccount: number;
/**
* Used signature algorithm. The same as used by merchant when creating the payment.
*/
checkoutAlgorithm: string;
/**
* HTTP verb of the request. Always POST for addcard-form.
*/
checkoutMethod: string;
/**
* Unique identifier for this request.
*/
checkoutNonce: string;
/**
* ISO 8601 date time.
*/
checkoutTimestamp: string;
/**
* Merchant's url for user redirect on successful card addition.
*/
Expand All @@ -33,10 +13,6 @@ export declare class AddCardFormRequest {
* Merchant's url for user redirect on failed card addition.
*/
checkoutRedirectCancelUrl: string;
/**
* Signature calculated from 'checkout-' prefixed POST parameters the same way as calculating signature from headers.
*/
signature: string;
/**
* Merchant's url called on successful card addition.
*/
Expand Down
30 changes: 0 additions & 30 deletions dist/models/request/add-card-form.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,31 +20,6 @@ const class_validator_1 = require("class-validator");
class AddCardFormRequest {
}
exports.AddCardFormRequest = AddCardFormRequest;
__decorate([
(0, class_validator_1.IsNotEmpty)(),
(0, class_validator_1.IsNumber)(),
__metadata("design:type", Number)
], AddCardFormRequest.prototype, "checkoutAccount", void 0);
__decorate([
(0, class_validator_1.IsNotEmpty)(),
(0, class_validator_1.IsString)(),
__metadata("design:type", String)
], AddCardFormRequest.prototype, "checkoutAlgorithm", void 0);
__decorate([
(0, class_validator_1.IsNotEmpty)(),
(0, class_validator_1.IsString)(),
__metadata("design:type", String)
], AddCardFormRequest.prototype, "checkoutMethod", void 0);
__decorate([
(0, class_validator_1.IsNotEmpty)(),
(0, class_validator_1.IsString)(),
__metadata("design:type", String)
], AddCardFormRequest.prototype, "checkoutNonce", void 0);
__decorate([
(0, class_validator_1.IsNotEmpty)(),
(0, class_validator_1.IsString)(),
__metadata("design:type", String)
], AddCardFormRequest.prototype, "checkoutTimestamp", void 0);
__decorate([
(0, class_validator_1.IsNotEmpty)(),
(0, class_validator_1.IsString)(),
Expand All @@ -55,11 +30,6 @@ __decorate([
(0, class_validator_1.IsString)(),
__metadata("design:type", String)
], AddCardFormRequest.prototype, "checkoutRedirectCancelUrl", void 0);
__decorate([
(0, class_validator_1.IsNotEmpty)(),
(0, class_validator_1.IsString)(),
__metadata("design:type", String)
], AddCardFormRequest.prototype, "signature", void 0);
__decorate([
(0, class_validator_1.IsString)(),
(0, class_validator_1.IsOptional)(),
Expand Down
2 changes: 2 additions & 0 deletions dist/models/request/create-payment.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const callback_url_model_1 = require("./request-model/callback-url.model");
const payment_method_group_model_1 = require("./request-model/payment-method-group.model");
const class_transformer_1 = require("class-transformer");
require("reflect-metadata");
const create_payment_validator_1 = require("../../validators/create-payment.validator");
/**
* Class CreatePaymentRequest
*
Expand Down Expand Up @@ -66,6 +67,7 @@ __decorate([
(0, class_validator_1.IsOptional)(),
(0, class_validator_1.ValidateNested)({ each: true }),
(0, class_transformer_1.Type)(() => item_model_1.Item),
(0, create_payment_validator_1.ValidateItemPrices)(),
__metadata("design:type", Array)
], CreatePaymentRequest.prototype, "items", void 0);
__decorate([
Expand Down
9 changes: 3 additions & 6 deletions dist/models/request/request-model/item.model.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Commission } from './commission.model';
import 'reflect-metadata';
/**
* Class Item
Expand All @@ -11,6 +10,9 @@ export declare class Item {
/**
* Price per unit, VAT included, in each country's
* minor unit, e.g. for Euros use cents.
* Min value -2147483648, max value 2147483647.
* Negative values are not allowed when usePricesWithoutVat is true
* or for Shop-in-Shop items.
*/
unitPrice: number;
/**
Expand Down Expand Up @@ -61,9 +63,4 @@ export declare class Item {
* Required for Shop-in-Shop payments, do not use for normal payments.
*/
merchant?: string;
/**
* Shop-in-Shop commission.
* Do not use for normal payments.
*/
commission?: Commission;
}
9 changes: 0 additions & 9 deletions dist/models/request/request-model/item.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ var __metadata = (this && this.__metadata) || function (k, v) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.Item = void 0;
const class_validator_1 = require("class-validator");
const commission_model_1 = require("./commission.model");
const class_transformer_1 = require("class-transformer");
require("reflect-metadata");
/**
* Class Item
Expand All @@ -27,7 +25,6 @@ exports.Item = Item;
__decorate([
(0, class_validator_1.IsNotEmpty)(),
(0, class_validator_1.IsNumber)(),
(0, class_validator_1.Min)(0),
__metadata("design:type", Number)
], Item.prototype, "unitPrice", void 0);
__decorate([
Expand Down Expand Up @@ -82,9 +79,3 @@ __decorate([
(0, class_validator_1.Length)(0, 50),
__metadata("design:type", String)
], Item.prototype, "merchant", void 0);
__decorate([
(0, class_validator_1.IsOptional)(),
(0, class_validator_1.ValidateNested)(),
(0, class_transformer_1.Type)(() => commission_model_1.Commission),
__metadata("design:type", commission_model_1.Commission)
], Item.prototype, "commission", void 0);
18 changes: 14 additions & 4 deletions dist/models/request/request-model/shop-in-shop-item.model.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
import { Item } from './item.model';
import { Commission } from './commission.model';
import 'reflect-metadata';
/**
* Class ShopInShopItem
*
* Shop-in-Shop item extends the base Item class with specific validations:
* - stamp is required
* - reference is required
* - merchant is required
* - commission can be given but is optional
* - unitPrice minimum is 0 (no negative values allowed)
*/
export declare class ShopInShopItem {
export declare class ShopInShopItem extends Item {
/**
* Item level order ID (suborder ID). Mainly useful for Shop-in-Shop purchases.
* Price per unit, VAT included, in each country's
* minor unit, e.g. for Euros use cents.
* For Shop-in-Shop items, negative values are not allowed.
*/
orderId?: string;
unitPrice: number;
/**
* Unique identifier for this item. Required for Shop-in-Shop payments. Required for item refunds.
*/
Expand All @@ -21,7 +31,7 @@ export declare class ShopInShopItem {
*/
merchant: string;
/**
* Shop-in-Shop commission. Do not use for normal payments.
* Shop-in-Shop commission. Optional for Shop-in-Shop payments only.
*/
commission?: Commission;
}
22 changes: 16 additions & 6 deletions dist/models/request/request-model/shop-in-shop-item.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,29 @@ var __metadata = (this && this.__metadata) || function (k, v) {
Object.defineProperty(exports, "__esModule", { value: true });
exports.ShopInShopItem = void 0;
const class_validator_1 = require("class-validator");
const commission_model_1 = require("./commission.model");
const item_model_1 = require("./item.model");
const class_transformer_1 = require("class-transformer");
const commission_model_1 = require("./commission.model");
require("reflect-metadata");
/**
* Class ShopInShopItem
*
* Shop-in-Shop item extends the base Item class with specific validations:
* - stamp is required
* - reference is required
* - merchant is required
* - commission can be given but is optional
* - unitPrice minimum is 0 (no negative values allowed)
*/
class ShopInShopItem {
class ShopInShopItem extends item_model_1.Item {
}
exports.ShopInShopItem = ShopInShopItem;
__decorate([
(0, class_validator_1.IsOptional)(),
(0, class_validator_1.IsString)(),
__metadata("design:type", String)
], ShopInShopItem.prototype, "orderId", void 0);
(0, class_validator_1.IsNumber)(),
(0, class_validator_1.Min)(0),
(0, class_validator_1.Max)(2147483647),
__metadata("design:type", Number)
], ShopInShopItem.prototype, "unitPrice", void 0);
__decorate([
(0, class_validator_1.IsNotEmpty)(),
__metadata("design:type", String)
Expand All @@ -38,6 +47,7 @@ __decorate([
__metadata("design:type", String)
], ShopInShopItem.prototype, "merchant", void 0);
__decorate([
(0, class_validator_1.IsOptional)(),
(0, class_validator_1.ValidateNested)(),
(0, class_transformer_1.Type)(() => commission_model_1.Commission),
__metadata("design:type", commission_model_1.Commission)
Expand Down
4 changes: 0 additions & 4 deletions dist/models/response/add-card-form.model.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ export declare class AddCardFormResponse extends Response {
* Class AddCardFormData
*/
export declare class AddCardFormData {
/**
* Assigned transaction ID for the payment.
*/
transactionId: string;
/**
* URL to hosted payment gateway.
*/
Expand Down
39 changes: 34 additions & 5 deletions dist/paytrail-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const variable_constant_1 = require("./constants/variable.constant");
const models_1 = require("./models");
const paytrail_1 = require("./paytrail");
const axios_util_1 = require("./utils/axios.util");
const convert_object_keys_util_1 = require("./utils/convert-object-keys.util");
const convert_object_to_class_utils_1 = require("./utils/convert-object-to-class.utils");
const signature_util_1 = require("./utils/signature.util");
const validate_error_utils_1 = require("./utils/validate-error.utils");
Expand Down Expand Up @@ -212,11 +213,39 @@ class PaytrailClient extends paytrail_1.Paytrail {
}
createAddCardFormRequest(addCardFormRequest) {
return __awaiter(this, void 0, void 0, function* () {
try {
return yield this.callApi(() => axios_util_1.api.tokenPayments.createAddCardFormRequest(addCardFormRequest), models_1.AddCardFormResponse, () => (0, validate_error_utils_1.validateError)((0, convert_object_to_class_utils_1.convertObjectToClass)(addCardFormRequest, models_1.AddCardFormRequest)), null, null);
}
catch (error) {
throw new Error(error === null || error === void 0 ? void 0 : error.message);
// eslint-disable-next-line no-useless-catch
try {
const currentDate = new Date().toISOString();
const payload = Object.assign(Object.assign({}, addCardFormRequest), { checkoutAccount: this.merchantId, checkoutAlgorithm: 'sha256', checkoutMethod: 'POST', checkoutTimestamp: currentDate, checkoutNonce: signature_util_1.Signature.encodeMD5(currentDate) });
const converted = (0, convert_object_keys_util_1.convertObjectKeys)(payload);
const hparams = {};
Object.keys(converted).forEach((key) => {
if (key.startsWith('checkout-')) {
hparams[key] = converted[key];
}
});
payload.signature = signature_util_1.Signature.calculateHmac(this.secretKey, hparams, '');
return yield this.callApi(() => __awaiter(this, void 0, void 0, function* () {
try {
const data = yield axios_util_1.api.tokenPayments.createAddCardFormRequest(payload);
// If the response is { data: { redirectUrl } }
if (data && 'data' in data && data.data && 'redirectUrl' in data.data) {
return [undefined, data.data];
}
return [undefined, data];
}
catch (error) {
// If error is an object with status, pass it as the first tuple element
if (error && typeof error === 'object' && 'status' in error) {
return [error, undefined];
}
// Otherwise, treat as generic error
return [error, undefined];
}
}), models_1.AddCardFormResponse, () => (0, validate_error_utils_1.validateError)((0, convert_object_to_class_utils_1.convertObjectToClass)(addCardFormRequest, models_1.AddCardFormRequest)), null, null);
}
catch (error) {
throw error;
}
});
}
Expand Down
1 change: 1 addition & 0 deletions dist/paytrail.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export declare abstract class Paytrail {
handleResponse<T>(type: string, targetClass: any, data?: any, dataError?: {
message: string | boolean;
status: number;
data?: any;
}): T;
/**
* Call an API, validate the response, and return an instance of the specified class.
Expand Down
Loading