test(billing-platform): transfer finalization test
ADD
src/assets/server/rest/v1/schemas/billing/billing-transfer-finalize.json
+{
+ "$id": "billing-transfers-finalize",
+ "title": "Finalize transfer Request",
+ "type": "object",
+ "properties": {
+ "ID": {
+ "$ref": "common#/definitions/id"
+ }
+ },
+ "required": [
+ "ID"
+ ]
+}

MODIFY
src/server/rest/v1/router/api/BillingRouter.ts
src/server/rest/v1/router/api/BillingRouter.ts
@@ -181,7 +181,8 @@ export default class BillingRouter {
}
private buildRouteBillingFinalizeTransfer(): void {
- this.router.get(`/${RESTServerRoute.REST_BILLING_TRANSFER_FINALIZE}`, (req: Request, res: Response, next: NextFunction) => {
+ this.router.patch(`/${RESTServerRoute.REST_BILLING_TRANSFER_FINALIZE}`, (req: Request, res: Response, next: NextFunction) => {
+ req.params.ID = req.params.id;
void RouterUtils.handleRestServerAction(BillingService.handleFinalizeTransfer.bind(this), ServerAction.BILLING_TRANSFER_FINALIZE, req, res, next);
});
}

MODIFY
src/server/rest/v1/service/AuthorizationService.ts
src/server/rest/v1/service/AuthorizationService.ts
@@ -625,7 +625,7 @@ export default class AuthorizationService {
return authorizations;
}
- public static async checkAndGetBillingTransfersAuthorizations(tenant: Tenant, userToken: UserToken,
+ public static async checkAndGetBillingTransfersAuthorizations(tenant: Tenant, userToken: UserToken, authAction: Action,
filteredRequest?: Partial<HttpBillingTransfersGetRequest>, failsWithException = true): Promise<AuthorizationFilter> {
const authorizations: AuthorizationFilter = {
filters: {},
@@ -635,7 +635,7 @@ export default class AuthorizationService {
};
// Check static & dynamic authorization
await this.canPerformAuthorizationAction(
- tenant, userToken, Entity.BILLING_TRANSFER, Action.LIST, authorizations, filteredRequest, null, failsWithException);
+ tenant, userToken, Entity.BILLING_TRANSFER, authAction, authorizations, filteredRequest, null, failsWithException);
return authorizations;
}

MODIFY
src/server/rest/v1/service/BillingService.ts
src/server/rest/v1/service/BillingService.ts
@@ -578,7 +578,7 @@ export default class BillingService {
Action.BILLING_ONBOARD_SUB_ACCOUNT, Entity.BILLING_SUB_ACCOUNT, MODULE_NAME, 'handleOnboardAccount');
const filteredRequest = BillingValidatorRest.getInstance().validateBillingSubAccountGetReq(req.params);
// Check authorization
- await AuthorizationService.checkAndGetBillingSubAccountAuthorizations(req.tenant, req.user, filteredRequest, Action.BILLING_ONBOARD_SUB_ACCOUNT);
+ await AuthorizationService.checkAndGetBillingTransfersAuthorizations(req.tenant, req.user, Action.BILLING_ONBOARD_SUB_ACCOUNT);
const subAccount = await BillingStorage.getSubAccountByID(req.tenant, filteredRequest.ID);
UtilsService.assertObjectExists(action, subAccount, `Sub account ID '${filteredRequest.ID}' does not exist`, MODULE_NAME, 'handleOnboardAccount', req.user);
// Check if the sub account onboarding is already sent
@@ -608,7 +608,7 @@ export default class BillingService {
// Filter
const filteredRequest = BillingValidatorRest.getInstance().validateBillingTransfersGetReq(req.query);
// Check auth
- const authorizations = await AuthorizationService.checkAndGetBillingTransfersAuthorizations(req.tenant, req.user, filteredRequest /* , false */);
+ const authorizations = await AuthorizationService.checkAndGetBillingTransfersAuthorizations(req.tenant, req.user, Action.LIST, filteredRequest /* , false */);
if (!authorizations.authorized) {
UtilsService.sendEmptyDataResult(res, next);
return;
@@ -639,7 +639,7 @@ export default class BillingService {
Action.BILLING_FINALIZE_TRANSFER, Entity.BILLING_TRANSFER, MODULE_NAME, 'handleFinalizeTransfer');
const filteredRequest = BillingValidatorRest.getInstance().validateBillingTransferFinalizeReq(req.params);
// Check authorization
- await AuthorizationService.checkAndGetBillingSubAccountAuthorizations(req.tenant, req.user, filteredRequest, Action.BILLING_FINALIZE_TRANSFER);
+ await AuthorizationService.checkAndGetBillingTransfersAuthorizations(req.tenant, req.user, Action.BILLING_FINALIZE_TRANSFER);
const transfer = await BillingStorage.getTransferByID(req.tenant, filteredRequest.ID);
UtilsService.assertObjectExists(action, transfer, `Transfer ID '${filteredRequest.ID}' does not exist`, MODULE_NAME, 'handleFinalizeTransfer', req.user);
// Check if the transfer is in draft status

MODIFY
test/api/BillingTest.ts
test/api/BillingTest.ts
/* eslint-disable max-len */
-import { BillingAccount, BillingAccountStatus, BillingChargeInvoiceAction, BillingInvoiceStatus } from '../../src/types/Billing';
+import { BillingAccount, BillingAccountStatus, BillingChargeInvoiceAction, BillingInvoiceStatus, BillingTransferStatus } from '../../src/types/Billing';
import { BillingPlatformFeeStrategyFactory, BillingTransferFactory } from '../factories/BillingFactory';
import { BillingSettings, BillingSettingsType } from '../../src/types/Setting';
import chai, { expect } from 'chai';
@@ -1221,6 +1221,26 @@ describeif(isBillingProperlyConfigured)('Billing', () => {
delete savedTransfer.lastChangedBy;
expect(savedTransfer).to.containSubset(transfer);
});
+
+ it('should finalize transfer', async () => {
+ const transfer = BillingTransferFactory.build();
+ transfer.status = BillingTransferStatus.DRAFT;
+ const transferID = await BillingStorage.saveTransfer(billingTestHelper.tenantContext.getTenant(), transfer);
+ transfer.id = transferID;
+ const finalizeResponse = await billingTestHelper.userService.billingApi.finalizeTransfer(transferID);
+ expect(finalizeResponse.status).to.be.eq(StatusCodes.OK);
+ const finalizedTransfer = await BillingStorage.getTransferByID(billingTestHelper.tenantContext.getTenant(), transferID);
+ expect(finalizedTransfer.status).to.eq(BillingTransferStatus.FINALIZED);
+ });
+
+ it('should not finalize not draft transfer', async () => {
+ const transfer = BillingTransferFactory.build();
+ transfer.status = BillingTransferStatus.FINALIZED;
+ const transferID = await BillingStorage.saveTransfer(billingTestHelper.tenantContext.getTenant(), transfer);
+ transfer.id = transferID;
+ const finalizeResponse = await billingTestHelper.userService.billingApi.finalizeTransfer(transferID);
+ expect(finalizeResponse.status).to.be.eq(StatusCodes.INTERNAL_SERVER_ERROR);
+ });
});
});
@@ -1236,6 +1256,7 @@ describeif(isBillingProperlyConfigured)('Billing', () => {
expect(billingTestHelper.userService).to.not.be.null;
});
+ describe('Sub accounts', () => {
it('should not be able to create a sub account', async () => {
const response = await billingTestHelper.userService.billingApi.createSubAccount({
businessOwnerID: billingTestHelper.userContext.id
@@ -1267,11 +1288,19 @@ describeif(isBillingProperlyConfigured)('Billing', () => {
const subAccountResponse = await billingTestHelper.userService.billingApi.sendSubAccountOnboarding('62978713f146ea8cb3bf8a95'); // inexistent sub account
expect(subAccountResponse.status).to.be.eq(StatusCodes.FORBIDDEN);
});
+ });
+ describe('Transfers', () => {
it('should not be able to list transfers', async () => {
const transfersResponse = await billingTestHelper.userService.billingApi.readTransfers({});
expect(transfersResponse.status).to.be.eq(StatusCodes.FORBIDDEN);
});
+
+ it('should not be able to finalize a transfer', async () => {
+ const finalizeResponse = await billingTestHelper.userService.billingApi.finalizeTransfer('5ce249a1a39ae1c056c389bd'); // inexistent transfer
+ expect(finalizeResponse.status).to.be.eq(StatusCodes.FORBIDDEN);
+ });
+ });
});
describe('Storage', () => {

MODIFY
test/api/client/BillingApi.ts
test/api/client/BillingApi.ts
@@ -75,4 +75,8 @@ export default class BillingApi extends CrudApi {
public async readTransfers(params, paging = TestConstants.DEFAULT_PAGING, ordering = TestConstants.DEFAULT_ORDERING) {
return super.readAll(params, paging, ordering, super.buildRestEndpointUrl(RESTServerRoute.REST_BILLING_TRANSFERS));
}
+
+ public async finalizeTransfer(id) {
+ return super.patch({}, super.buildRestEndpointUrl(RESTServerRoute.REST_BILLING_TRANSFER_FINALIZE, { id }));
+ }
}

test(billing-platform): transfer finalization test