From cb63a3c4f640d0b68300a717d9a959e33ff93ac1 Mon Sep 17 00:00:00 2001 From: Santiago Botero <98826652+boterop@users.noreply.github.com> Date: Tue, 14 Jan 2025 12:58:10 -0500 Subject: [PATCH 1/4] Complete coverage (#14) * Coveralls badge * App tests * Amount type test * Add payment link tests * Complete http client tests --- README.md | 2 +- src/domain/payment_link.js | 2 +- src/domain/payment_methods.js | 2 +- src/services/index.js | 1 + src/services/payment_link.js | 4 +-- tests/app.test.js | 25 ++++++++++++++ tests/domain/payment_link.test.js | 56 +++++++++++++++++++++++++++---- tests/shared/http_client.test.js | 46 +++++++++++++++++++++++++ 8 files changed, 126 insertions(+), 12 deletions(-) create mode 100644 tests/app.test.js diff --git a/README.md b/README.md index 5c5858a..4fbf359 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Coverage Status](https://coveralls.io/repos/github/boterop/bold/badge.svg?branch=main)](https://coveralls.io/github/boterop/bold?branch=main) +[![Coverage Status](https://coveralls.io/repos/github/boterop/bold-api-sdk/badge.svg?branch=add-types)](https://coveralls.io/github/boterop/bold-api-sdk?branch=add-types) ![NPM Type Definitions](https://img.shields.io/npm/types/bold-api-sdk) # bold-api-sdk diff --git a/src/domain/payment_link.js b/src/domain/payment_link.js index f7d32e6..e144ff4 100644 --- a/src/domain/payment_link.js +++ b/src/domain/payment_link.js @@ -1,4 +1,4 @@ -const paymentLinkService = require('../services/payment_link'); +const { paymentLinkService } = require('../services'); const paymentLink = { create: async (apiKey, order) => paymentLinkService.create(apiKey, order), diff --git a/src/domain/payment_methods.js b/src/domain/payment_methods.js index 2c61e0b..df352cb 100644 --- a/src/domain/payment_methods.js +++ b/src/domain/payment_methods.js @@ -1,4 +1,4 @@ -const paymentMethodsService = require('../services/payment_methods'); +const { paymentMethodsService } = require('../services'); const paymentMethods = { list: async apiKey => paymentMethodsService.list(apiKey), diff --git a/src/services/index.js b/src/services/index.js index 94a1c1e..a74aa31 100644 --- a/src/services/index.js +++ b/src/services/index.js @@ -1 +1,2 @@ +exports.paymentLinkService = require('./payment_link'); exports.paymentMethodsService = require('./payment_methods'); diff --git a/src/services/payment_link.js b/src/services/payment_link.js index 20d579a..ebc95f0 100644 --- a/src/services/payment_link.js +++ b/src/services/payment_link.js @@ -8,7 +8,7 @@ exports.create = async ( payerEmail, amount, callbackUrl, - expirationMinutes, + expirationMinutes = 30, currency, }, ) => { @@ -17,7 +17,7 @@ exports.create = async ( } const currentNanoseconds = Date.now() * 1e6; - const minutesInNanoseconds = (expirationMinutes || 30) * 60 * 1e9; + const minutesInNanoseconds = expirationMinutes * 60 * 1e9; const futureNanoseconds = currentNanoseconds + minutesInNanoseconds; const amountOpt = diff --git a/tests/app.test.js b/tests/app.test.js new file mode 100644 index 0000000..e9649fb --- /dev/null +++ b/tests/app.test.js @@ -0,0 +1,25 @@ +const fs = require('fs'); +const path = require('path'); +const boldApiSdk = require('../src/app'); + +const fileToExportKey = key => { + const newKey = key + .split('.') + .shift() + .split('_') + .map(s => s[0].toUpperCase() + s.slice(1)) + .join(''); + + return newKey[0].toLowerCase() + newKey.slice(1); +}; + +describe('boldApiSdk', () => { + it('should export all domains', () => { + const domains = fs.readdirSync(path.join(__dirname, '../src/domain')); + + for (const domain of domains) { + const key = fileToExportKey(domain); + expect(boldApiSdk[key]).toBeDefined(); + } + }); +}); diff --git a/tests/domain/payment_link.test.js b/tests/domain/payment_link.test.js index 8fba154..9437d51 100644 --- a/tests/domain/payment_link.test.js +++ b/tests/domain/payment_link.test.js @@ -9,11 +9,14 @@ describe('paymentLink', () => { const callbackUrl = 'https://example.org/return'; const expirationMinutes = 30; const currency = 'USD'; + const apiKey = 'bold-api-key'; - it('should return a payment link', async () => { + beforeEach(() => { process.env.BOLD_API_URL = 'https://example.org'; + }); - const response = await paymentLink.create('bold-api-key', { + it('should return a payment link', async () => { + const response = await paymentLink.create(apiKey, { amountType, description, payerEmail, @@ -37,11 +40,8 @@ describe('paymentLink', () => { expect(body.payer_email).toBe(payerEmail); }); - it('should not send amount if type is not CLOSE', async () => { - process.env.BOLD_API_URL = 'https://example.org'; - - const response = await paymentLink.create('bold-api-key', { - amountType: 'OPEN', + it('should not send amount if type is OPEN', async () => { + const response = await paymentLink.create(apiKey, { description, payerEmail, amount, @@ -55,5 +55,47 @@ describe('paymentLink', () => { expect(url).toBe('https://example.org/online/link/v1'); expect(body.amount).toBeUndefined(); }); + + it('should set default values if not provided', async () => { + const response = await paymentLink.create(apiKey, { + amountType, + }); + + const { options } = response; + const body = JSON.parse(options.body); + + const expirationMinutes = 30; + const currentNanoseconds = Date.now() * 1e6; + const minutesInNanoseconds = expirationMinutes * 60 * 1e9; + const futureNanoseconds = currentNanoseconds + minutesInNanoseconds; + + expect(body.amount_type).toBe('CLOSE'); + expect(body.amount.total_amount).toBe(0); + expect(body.amount.currency).toBe('COP'); + expect(Math.abs(body.expiration_date - futureNanoseconds)).toBeLessThan( + 0.1 * 1e9, + ); + expect(body.callback_url).toBe(''); + expect(body.payer_email).toBe(''); + expect(body.description).toBe(''); + }); + + it('should send error if amount type is not CLOSE or OPEN', async () => { + try { + await paymentLink.create(apiKey, { + amountType: 'INVALID', + description, + payerEmail, + amount, + callbackUrl, + expirationMinutes, + currency, + }); + } catch (error) { + expect(error.message).toBe( + 'Invalid amount type, must be CLOSE or OPEN', + ); + } + }); }); }); diff --git a/tests/shared/http_client.test.js b/tests/shared/http_client.test.js index f182dfa..06bcced 100644 --- a/tests/shared/http_client.test.js +++ b/tests/shared/http_client.test.js @@ -20,5 +20,51 @@ describe('httpClient', () => { ); expect(response.options.headers['Content-Type']).toBe('application/json'); }); + + it('should parse url with / at the end', async () => { + const response = await httpClient.fetch({ + url: URL + '/', + endpoint: ENDPOINT.replace('/', ''), + apiKey: API_KEY, + }); + expect(response.url).toBe(`${URL}${ENDPOINT}`); + }); + + it('should get api key from process.env if not provided', async () => { + process.env.BOLD_API_KEY = API_KEY; + + const response = await httpClient.fetch({ + url: URL, + endpoint: ENDPOINT, + }); + + expect(response.url).toBe(`${URL}${ENDPOINT}`); + expect(response.options.headers.Authorization).toBe( + `x-api-key ${API_KEY}`, + ); + }); + + it('should use just url if no endpoint is provided', async () => { + const response = await httpClient.fetch({ + url: URL, + }); + expect(response.url).toBe(`${URL}/`); + }); + + it('should use default url if no url is provided', async () => { + const response = await httpClient.fetch({ + endpoint: ENDPOINT, + }); + expect(response.url).toBe(`https://integrations.api.bold.co${ENDPOINT}`); + }); + + it('should get url from process.env if not provided', async () => { + process.env.BOLD_API_URL = URL; + + const response = await httpClient.fetch({ + endpoint: ENDPOINT, + }); + expect(response.url).toBe(`${URL}${ENDPOINT}`); + }); }); }); From 5642707e8daa922dac1533139d99393342fd84a3 Mon Sep 17 00:00:00 2001 From: Santiago Botero <98826652+boterop@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:42:10 -0500 Subject: [PATCH 2/4] Taxes and tests (#15) * Taxes and tests * Save .env.test with ci secret * Remove .env.test after testing * Test iva * Let user enter iva value * Improve function --- .env.test.example | 1 + .github/workflows/ci.yml | 5 +- README.md | 2 + jest.config.js | 9 +++- package.json | 2 +- src/app.d.ts | 16 +++--- src/services/payment_link.js | 36 +++++++++++--- tests/domain/payment_link.test.js | 75 ++++++++++++++--------------- tests/domain/payment_methds.test.js | 16 +++--- tests/runtime.js | 3 -- tests/shared/http_client.test.js | 12 +++++ tests/test_helper.js | 5 -- 12 files changed, 109 insertions(+), 73 deletions(-) create mode 100644 .env.test.example delete mode 100644 tests/runtime.js delete mode 100644 tests/test_helper.js diff --git a/.env.test.example b/.env.test.example new file mode 100644 index 0000000..f70a355 --- /dev/null +++ b/.env.test.example @@ -0,0 +1 @@ +BOLD_API_KEY= diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a64a1b..72e6813 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,9 @@ jobs: - name: Check Format run: yarn check-format - name: Run Tests - run: yarn test + run: | + echo BOLD_API_KEY=${{ secrets.BOLD_API_KEY }} > .env.test + yarn test + rm -Rf .env.test - name: Coveralls uses: coverallsapp/github-action@v2 diff --git a/README.md b/README.md index 4fbf359..0f427b6 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,11 @@ const response = await paymentLink.create('bold-identity-key', { description: 'Payment for order order-id', payerEmail: 'test@example.org', amount: 300, + tipAmount: 0, currency: 'USD', callbackUrl: 'https://example.org/return', expirationMinutes: 30, + iva: 19, }); console.log(response); diff --git a/jest.config.js b/jest.config.js index f9fd922..2dd35f7 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,10 +1,15 @@ process.env.NODE_ENV = 'test'; +// Load environment variables +try { + process.loadEnvFile(process.cwd() + '/.env.test'); +} catch (_error) { + logger.info('No se encontrĂ³ el archivo de variables de entorno .env.test'); +} + module.exports = { testEnvironment: 'node', moduleFileExtensions: ['js', 'json'], - setupFiles: ['./tests/test_helper.js'], - setupFilesAfterEnv: ['./tests/runtime.js'], transform: { '^.+\\.js?$': 'babel-jest', }, diff --git a/package.json b/package.json index c7758ba..6e7175e 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "types": "src/app.d.ts", "scripts": { "start": "node --env-file .env --watch src/app.js", - "test": "NODE_ENV=test node --experimental-vm-modules --max-old-space-size=8192 node_modules/jest/bin/jest.js --detectOpenHandles --runInBand", + "test": "NODE_ENV=test node --experimental-vm-modules --max-old-space-size=8192 node_modules/jest/bin/jest.js --runInBand", "format": "prettier --write .", "check-format": "prettier -c .", "lint": "eslint ." diff --git a/src/app.d.ts b/src/app.d.ts index f240a7d..426fab7 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -1,12 +1,14 @@ declare module 'bold-api-sdk' { export interface Order { - amountType: 'OPEN' | 'CLOSE'; - description: string; - payerEmail: string; - amount: number; - callbackUrl: string; - expirationMinutes: number; - currency: string; + amountType?: 'OPEN' | 'CLOSE'; + description?: string; + payerEmail?: string; + amount?: number; + tipAmount?: number; + callbackUrl?: string; + expirationMinutes?: number; + currency?: string; + iva?: number; } export interface LinkResponse { diff --git a/src/services/payment_link.js b/src/services/payment_link.js index ebc95f0..5052e6f 100644 --- a/src/services/payment_link.js +++ b/src/services/payment_link.js @@ -3,29 +3,49 @@ const { httpClient } = require('../shared'); exports.create = async ( apiKey, { - amountType = 'OPEN', + amountType, description, payerEmail, amount, + tipAmount, callbackUrl, - expirationMinutes = 30, + expirationMinutes, currency, - }, + iva, + } = {}, ) => { + amountType = amountType || 'OPEN'; + description = description || ''; + payerEmail = payerEmail || ''; + amount = Math.abs(amount) || 0; + tipAmount = Math.abs(tipAmount) || 0; + callbackUrl = callbackUrl || null; + expirationMinutes = expirationMinutes || 30; + currency = currency || 'COP'; + iva = iva || 0; + if (amountType !== 'CLOSE' && amountType !== 'OPEN') { throw new Error('Invalid amount type, must be CLOSE or OPEN'); } + const ivaValue = iva / 100; + const currentNanoseconds = Date.now() * 1e6; const minutesInNanoseconds = expirationMinutes * 60 * 1e9; const futureNanoseconds = currentNanoseconds + minutesInNanoseconds; + const hasTaxes = iva > 0; + const ivaTax = + iva > 0 ? { type: 'VAT', base: amount, value: amount * ivaValue } : null; + const amountOpt = amountType === 'CLOSE' ? { amount: { - total_amount: amount || 0, - currency: currency || 'COP', + total_amount: amount * (ivaValue + 1) + tipAmount, + currency, + tip_amount: tipAmount, + taxes: hasTaxes ? [ivaTax] : [], }, } : {}; @@ -38,10 +58,10 @@ exports.create = async ( body: JSON.stringify({ amount_type: amountType, ...amountOpt, - description: description || '', + description, expiration_date: futureNanoseconds, - callback_url: callbackUrl || '', - payer_email: payerEmail || '', + callback_url: callbackUrl, + payer_email: payerEmail, }), }, }); diff --git a/tests/domain/payment_link.test.js b/tests/domain/payment_link.test.js index 9437d51..4fb3097 100644 --- a/tests/domain/payment_link.test.js +++ b/tests/domain/payment_link.test.js @@ -1,18 +1,20 @@ const paymentLink = require('../../src/domain/payment_link'); describe('paymentLink', () => { + const PAYMENT_LINK = 'bold.co/payment'; + describe('create', () => { const amountType = 'CLOSE'; const description = 'Payment for order order-id'; const payerEmail = 'test@example.org'; - const amount = 300; + const amount = 1000; const callbackUrl = 'https://example.org/return'; const expirationMinutes = 30; - const currency = 'USD'; - const apiKey = 'bold-api-key'; + const currency = 'COP'; + const apiKey = process.env.BOLD_API_KEY || 'bold-api-key'; beforeEach(() => { - process.env.BOLD_API_URL = 'https://example.org'; + process.env.BOLD_API_URL = 'https://integrations.api.bold.co'; }); it('should return a payment link', async () => { @@ -25,19 +27,12 @@ describe('paymentLink', () => { expirationMinutes, currency, }); - const { url, options } = response; - const body = JSON.parse(options.body); - - expect(url).toBe('https://example.org/online/link/v1'); - expect(options.headers.Authorization).toBe('x-api-key bold-api-key'); - expect(options.method).toBe('POST'); - expect(body.amount_type).toBe(amountType); - expect(body.amount.total_amount).toBe(amount); - expect(body.amount.currency).toBe(currency); - expect(body.description).toBe(description); - expect(body.expiration_date).toBeGreaterThan(Date.now() * 1e6); - expect(body.callback_url).toBe(callbackUrl); - expect(body.payer_email).toBe(payerEmail); + + const { payload, errors } = response; + + expect(errors).toHaveLength(0); + + expect(payload.url).toContain(PAYMENT_LINK); }); it('should not send amount if type is OPEN', async () => { @@ -49,35 +44,37 @@ describe('paymentLink', () => { expirationMinutes, currency, }); - const { url, options } = response; - const body = JSON.parse(options.body); - expect(url).toBe('https://example.org/online/link/v1'); - expect(body.amount).toBeUndefined(); + const { payload, errors } = response; + + expect(errors).toHaveLength(0); + + expect(payload.url).toContain(PAYMENT_LINK); }); it('should set default values if not provided', async () => { + const response = await paymentLink.create(apiKey); + + const { payload, errors } = response; + + expect(errors).toHaveLength(0); + + expect(payload.url).toContain(PAYMENT_LINK); + }); + + it('should create a payment link with iva', async () => { const response = await paymentLink.create(apiKey, { - amountType, + amountType: 'CLOSE', + amount: 1000, + tipAmount: 100, + iva: 19, }); - const { options } = response; - const body = JSON.parse(options.body); - - const expirationMinutes = 30; - const currentNanoseconds = Date.now() * 1e6; - const minutesInNanoseconds = expirationMinutes * 60 * 1e9; - const futureNanoseconds = currentNanoseconds + minutesInNanoseconds; - - expect(body.amount_type).toBe('CLOSE'); - expect(body.amount.total_amount).toBe(0); - expect(body.amount.currency).toBe('COP'); - expect(Math.abs(body.expiration_date - futureNanoseconds)).toBeLessThan( - 0.1 * 1e9, - ); - expect(body.callback_url).toBe(''); - expect(body.payer_email).toBe(''); - expect(body.description).toBe(''); + const { payload, errors } = response; + + expect(errors).toHaveLength(0); + + expect(payload.url).toContain(PAYMENT_LINK); }); it('should send error if amount type is not CLOSE or OPEN', async () => { diff --git a/tests/domain/payment_methds.test.js b/tests/domain/payment_methds.test.js index c89dc73..cdd506e 100644 --- a/tests/domain/payment_methds.test.js +++ b/tests/domain/payment_methds.test.js @@ -3,14 +3,16 @@ const paymentMethods = require('../../src/domain/payment_methods'); describe('paymentMethods', () => { describe('list', () => { it('should return a list of payment methods', async () => { - process.env.BOLD_API_URL = 'https://example.org'; - const response = await paymentMethods.list('bold-api-key'); - const { url, options } = response; + process.env.BOLD_API_URL = 'https://integrations.api.bold.co'; + const response = await paymentMethods.list(); + const { payload, errors } = response; - expect(response).toBeDefined(); - expect(response).toBeInstanceOf(Object); - expect(url).toBe('https://example.org/online/link/v1/payment_methods'); - expect(options.headers.Authorization).toBe('x-api-key bold-api-key'); + expect(errors).toBeDefined(); + expect(errors).toHaveLength(0); + + expect(payload).toBeDefined(); + expect(payload.payment_methods).toBeDefined(); + expect(payload.payment_methods.CREDIT_CARD).toBeDefined(); }); }); }); diff --git a/tests/runtime.js b/tests/runtime.js deleted file mode 100644 index 9a97d5e..0000000 --- a/tests/runtime.js +++ /dev/null @@ -1,3 +0,0 @@ -beforeEach(() => { - global.fetch.mockClear(); -}); diff --git a/tests/shared/http_client.test.js b/tests/shared/http_client.test.js index 06bcced..c301cd9 100644 --- a/tests/shared/http_client.test.js +++ b/tests/shared/http_client.test.js @@ -5,6 +5,18 @@ describe('httpClient', () => { const ENDPOINT = '/test'; const API_KEY = 'api-key'; + beforeEach(() => { + global.fetch = jest.fn((url, options) => + Promise.resolve({ + json: () => Promise.resolve({ url, options }), + }), + ); + }); + + afterEach(() => { + global.fetch.mockRestore(); + }); + describe('fetch', () => { it('should return a response', async () => { const response = await httpClient.fetch({ diff --git a/tests/test_helper.js b/tests/test_helper.js deleted file mode 100644 index 4f7e9b3..0000000 --- a/tests/test_helper.js +++ /dev/null @@ -1,5 +0,0 @@ -global.fetch = jest.fn((url, options) => - Promise.resolve({ - json: () => Promise.resolve({ url, options }), - }), -); From 78f17ffd3b816c4c4c06ba80ea7fa8baa9560ac9 Mon Sep 17 00:00:00 2001 From: Santiago Botero <98826652+boterop@users.noreply.github.com> Date: Wed, 15 Jan 2025 16:54:56 -0500 Subject: [PATCH 3/4] Prepare to release v0.1.4 (#16) --- CHANGELOG.md | 4 +++ package-lock.json | 4 +-- package.json | 2 +- yarn.lock | 83 +++++++++++++++++++---------------------------- 4 files changed, 40 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e564a3..21c70be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.1.4 (15.01.2025) + +- Add iva and tip amount to payment link + ## 0.1.3 (13.01.2025) - Add typescript definitions diff --git a/package-lock.json b/package-lock.json index a955e79..01d865e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "bold-api-sdk", - "version": "0.1.3", + "version": "0.1.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "bold-api-sdk", - "version": "0.1.3", + "version": "0.1.4", "license": "MIT", "devDependencies": { "eslint": "^9.17.0", diff --git a/package.json b/package.json index 6e7175e..21a9ca2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "bold-api-sdk", - "version": "0.1.3", + "version": "0.1.4", "description": "A Node.js library for interacting with the Bold API, providing seamless integration to manage payments, customers, and transactions efficiently.", "main": "src/app.js", "repository": "https://github.com/boterop/bold-api-sdk", diff --git a/yarn.lock b/yarn.lock index 660f463..30ee85e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24,7 +24,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.3.tgz" integrity sha512-nHIxvKPniQXpmQLb0vhY3VaFb3S0YrTAwpOWJZh1wn3oJPjJk9Asva204PsBdmAE8vpzfHudT8DB0scYvy9q0g== -"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.0.0-0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.11.0", "@babel/core@^7.11.6", "@babel/core@^7.12.0", "@babel/core@^7.12.3", "@babel/core@^7.13.0", "@babel/core@^7.23.9", "@babel/core@^7.4.0 || ^8.0.0-0 <8.0.0", "@babel/core@^7.8.0", "@babel/core@7.26.0": +"@babel/core@7.26.0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": version "7.26.0" resolved "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz" integrity sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg== @@ -1001,7 +1001,7 @@ dependencies: eslint-visitor-keys "^3.4.3" -"@eslint-community/regexpp@^4.12.1", "@eslint-community/regexpp@^4.8.0", "@eslint-community/regexpp@4.12.1": +"@eslint-community/regexpp@4.12.1", "@eslint-community/regexpp@^4.12.1", "@eslint-community/regexpp@^4.8.0": version "4.12.1" resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz" integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== @@ -1337,7 +1337,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -1512,7 +1512,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.14.0: +acorn@^8.14.0: version "8.14.0" resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== @@ -1735,7 +1735,7 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" -browserslist@^4.24.0, browserslist@^4.24.3, "browserslist@>= 4.21.0": +browserslist@^4.24.0, browserslist@^4.24.3: version "4.24.4" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz" integrity sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A== @@ -2157,14 +2157,6 @@ eslint-plugin-sonarjs@^3.0.1: semver "7.6.3" typescript "^5" -eslint-scope@^8.2.0: - version "8.2.0" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz" - integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - eslint-scope@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" @@ -2173,6 +2165,14 @@ eslint-scope@5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" +eslint-scope@^8.2.0: + version "8.2.0" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz" + integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + eslint-visitor-keys@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" @@ -2188,7 +2188,7 @@ eslint-visitor-keys@^4.2.0: resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz" integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== -"eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0 || ^9.0.0", "eslint@^7.5.0 || ^8.0.0 || ^9.0.0", "eslint@^8.0.0 || ^9.0.0", "eslint@^8.57.0 || ^9.0.0", eslint@^9.17.0: +eslint@^9.17.0: version "9.17.0" resolved "https://registry.npmjs.org/eslint/-/eslint-9.17.0.tgz" integrity sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA== @@ -2397,6 +2397,11 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +fsevents@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -3095,7 +3100,7 @@ jest-resolve-dependencies@^29.7.0: jest-regex-util "^29.6.3" jest-snapshot "^29.7.0" -jest-resolve@*, jest-resolve@^29.7.0: +jest-resolve@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== @@ -3239,7 +3244,7 @@ jest-worker@^29.7.0: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@*, jest@^29.7.0: +jest@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== @@ -3417,26 +3422,19 @@ mimic-fn@^2.1.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^9.0.4: +minimatch@9.0.5, minimatch@^9.0.4: version "9.0.5" resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz" integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" -minimatch@9.0.5: - version "9.0.5" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz" - integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: - brace-expansion "^2.0.1" + brace-expansion "^1.1.7" ms@^2.1.3: version "2.1.3" @@ -3855,30 +3853,15 @@ scslre@0.3.0: refa "^0.12.0" regexp-ast-analysis "^0.7.0" -semver@^6.3.0, semver@^6.3.1: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.5.3: - version "7.6.3" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - -semver@^7.5.4: +semver@7.6.3, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0: version "7.6.3" resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== -semver@^7.6.0: - version "7.6.3" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== - -semver@7.6.3: - version "7.6.3" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" - integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== set-function-length@^1.2.2: version "1.2.2" @@ -4181,7 +4164,7 @@ typed-array-length@^1.0.7: possible-typed-array-names "^1.0.0" reflect.getprototypeof "^1.0.6" -typescript@^5, typescript@>=4.8.4, "typescript@>=4.8.4 <5.8.0": +typescript@^5: version "5.7.3" resolved "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz" integrity sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw== From c37b7b9095f9b1decc92de8908de14c846b51bb9 Mon Sep 17 00:00:00 2001 From: boterop Date: Wed, 15 Jan 2025 17:00:26 -0500 Subject: [PATCH 4/4] Apply abs to number instead of number | undefined --- src/services/payment_link.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/services/payment_link.js b/src/services/payment_link.js index 5052e6f..d0ac768 100644 --- a/src/services/payment_link.js +++ b/src/services/payment_link.js @@ -17,8 +17,8 @@ exports.create = async ( amountType = amountType || 'OPEN'; description = description || ''; payerEmail = payerEmail || ''; - amount = Math.abs(amount) || 0; - tipAmount = Math.abs(tipAmount) || 0; + amount = Math.abs(amount || 0); + tipAmount = Math.abs(tipAmount || 0); callbackUrl = callbackUrl || null; expirationMinutes = expirationMinutes || 30; currency = currency || 'COP';