doc(subaccounts): getOne/getMany endpoints doc
MODIFY
src/assets/server/rest/v1/docs/e-mobility-oas.json
src/assets/server/rest/v1/docs/e-mobility-oas.json
}
},
"/api/billing/sub-accounts": {
+ "get": {
+ "security": [
+ {
+ "bearerAuth": []
+ }
+ ],
+ "description": "Get Sub-Accounts",
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/UserIDs"
+ },
+ {
+ "in": "query",
+ "name": "Status",
+ "description": "Pipe separated invoice status (idle, pending, active)",
+ "required": false,
+ "schema": {
+ "type": "string"
+ }
+ },
+ {
+ "$ref": "#/components/parameters/StartDateTime"
+ },
+ {
+ "$ref": "#/components/parameters/EndDateTime"
+ },
+ {
+ "$ref": "#/components/parameters/Search"
+ },
+ {
+ "$ref": "#/components/parameters/Skip"
+ },
+ {
+ "$ref": "#/components/parameters/Limit"
+ },
+ {
+ "$ref": "#/components/parameters/SortFields"
+ }
+ ],
+ "tags": [
+ "Billing"
+ ],
+ "responses": {
+ "200": {
+ "description": "Return sub-accounts",
+ "content": {
+ "application/json": {
+ "schema": {
+ "type": "object",
+ "properties": {
+ "count": {
+ "type": "number",
+ "example": 1
+ },
+ "result": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/SubAccount"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "401": {
+ "$ref": "#/components/responses/UnauthorizedError"
+ },
+ "403": {
+ "$ref": "#/components/responses/ForbiddenError"
+ },
+ "500": {
+ "$ref": "#/components/responses/BackendError"
+ }
+ }
+ },
"post": {
"security": [
{
}
}
},
+ "/api/billing/sub-accounts/{id}": {
+ "get": {
+ "security": [
+ {
+ "bearerAuth": []
+ }
+ ],
+ "description": "Get Sub-Accounts",
+ "parameters": [
+ {
+ "in": "path",
+ "name": "id",
+ "description": "Sub-account ID",
+ "schema": {
+ "type": "string"
+ },
+ "required": true
+ }
+ ],
+ "tags": [
+ "Billing"
+ ],
+ "responses": {
+ "200": {
+ "description": "Return sub-account",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SubAccount"
+ }
+ }
+ }
+ },
+ "401": {
+ "$ref": "#/components/responses/UnauthorizedError"
+ },
+ "403": {
+ "$ref": "#/components/responses/ForbiddenError"
+ },
+ "500": {
+ "$ref": "#/components/responses/BackendError"
+ },
+ "550": {
+ "$ref": "#/components/responses/ResourceDoesNotExists"
+ }
+ }
+ }
+ },
"/api/invoices": {
"get": {
"security": [
}
}
}
+ },
+ "SubAccount": {
+ "type": "object",
+ "properties": {
+ "accountID": {
+ "type": "string"
+ },
+ "userID": {
+ "type": "string"
+ },
+ "id": {
+ "type": "string",
+ "readOnly": true
+ },
+ "user": {
+ "$ref": "#/components/schemas/User"
+ }
+ }
}
},
"parameters": {

MODIFY
src/authorization/AuthorizationsDefinition.ts
src/authorization/AuthorizationsDefinition.ts
@@ -395,7 +395,7 @@ export const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
resource: Entity.BILLING_PLATFORM,
action: [Action.BILLING_CREATE_SUB_ACCOUNT, Action.LIST, Action.READ],
attributes: [
- 'id', 'accountID', 'userID', 'user.id', 'user.firstName', 'user.lastName', 'user.email'
+ 'id', 'accountID', 'userID', 'user.id', 'user.firstName', 'user.lastName', 'user.email', 'status'
]
},
{ resource: Entity.TAX, action: [Action.LIST] },

MODIFY
src/server/rest/v1/service/BillingService.ts
src/server/rest/v1/service/BillingService.ts
@@ -523,16 +523,6 @@ export default class BillingService {
const subAccount = await BillingStorage.getSubAccountByID(tenant, filteredRequest.ID);
UtilsService.assertObjectExists(action, subAccount, `Sub account ID '${filteredRequest.ID}' does not exist`, MODULE_NAME, 'handleActivateSubAccount', req.user);
// Check if the sub account is already activated
- if (subAccount.status === BillingAccountStatus.IDLE) {
- throw new AppError({
- errorCode: HTTPError.GENERAL_ERROR,
- message: 'Sub account cannot be activated yet',
- detailedMessages: 'Activation link has not been sent',
- module: MODULE_NAME, method: 'handleActivateSubAccount',
- action: action,
- user: req.user
- });
- }
if (subAccount.status === BillingAccountStatus.ACTIVE) {
throw new AppError({
errorCode: HTTPError.GENERAL_ERROR,
@@ -592,7 +582,7 @@ export default class BillingService {
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.BILLING_PLATFORM,
Action.READ, Entity.BILLING_PLATFORM, MODULE_NAME, 'handleBillingGetSubAccount');
// Get the billing subacounts
- const subAccount = await UtilsService.checkAndGetBillingSubAccountAuthorization(req.tenant, req.user, filteredRequest.ID, Action.READ, action);
+ const subAccount = await UtilsService.checkAndGetBillingSubAccountAuthorization(req.tenant, req.user, filteredRequest.ID, Action.READ, action, null, {}, true);
res.json(subAccount);
next();
}

MODIFY
src/server/rest/v1/service/CompanyService.ts
src/server/rest/v1/service/CompanyService.ts
@@ -185,7 +185,7 @@ export default class CompanyService {
company.lastChangedBy = { 'id': req.user.id };
company.lastChangedOn = new Date();
// If the company is assigned to a billing sub-account, check if the billing is active
- if (filteredRequest.billingData.accountID) {
+ if (filteredRequest.billingData) {
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.BILLING_PLATFORM,
Action.CREATE, Entity.COMPANY, MODULE_NAME, 'handleUpdateCompany');
const billingSubAccount = await BillingStorage.getSubAccountByID(req.tenant, filteredRequest.billingData.accountID);

MODIFY
test/api/BillingTest.ts
test/api/BillingTest.ts
@@ -986,7 +986,7 @@ describeif(isBillingProperlyConfigured)('Billing', () => {
expect(response.data.accountID).to.not.be.null;
expect(response.data.userID).to.eq(billingTestHelper.userContext.id);
expect(response.data.activationLink).to.not.be.null;
- expect(response.data.pending).to.be.true;
+ expect(response.data.status).to.be.eq(BillingAccountStatus.IDLE);
});
it('should create a sub account and activate it', async () => {
@@ -997,7 +997,7 @@ describeif(isBillingProperlyConfigured)('Billing', () => {
const activationResponse = await billingTestHelper.userService.billingApi.activateSubAccount({ accountID: response.data.id, TenantID: billingTestHelper.tenantContext.getTenant().id });
expect(activationResponse.status).to.be.eq(StatusCodes.OK);
- expect(activationResponse.data.pending).to.be.false;
+ expect(activationResponse.data.status).to.be.eq(BillingAccountStatus.ACTIVE);
});
it('should not activate an inexistent sub account', async () => {
@@ -1017,16 +1017,6 @@ describeif(isBillingProperlyConfigured)('Billing', () => {
expect(activationResponse.status).to.be.eq(StatusCodes.INTERNAL_SERVER_ERROR);
});
- it('should not activate an idled sub-account', async () => {
- const response = await billingTestHelper.userService.billingApi.createSubAccount({
- userID: billingTestHelper.userContext.id
- });
- expect(response.status).to.be.eq(StatusCodes.CREATED);
-
- const activationResponse = await billingTestHelper.userService.billingApi.activateSubAccount({ accountID: response.data.id, TenantID: billingTestHelper.tenantContext.getTenant().id });
- expect(activationResponse.status).to.be.eq(StatusCodes.INTERNAL_SERVER_ERROR);
- });
-
it('should create a company assigned to a sub-account', async () => {
const subAccountResponse = await billingTestHelper.userService.billingApi.createSubAccount({
userID: billingTestHelper.userContext.id
@@ -1171,6 +1161,12 @@ describeif(isBillingProperlyConfigured)('Billing', () => {
const subAccountsResponse = await billingTestHelper.userService.billingApi.readAllSubAccounts({});
expect(subAccountsResponse.status).to.be.eq(StatusCodes.FORBIDDEN);
});
+
+ it('should not be able to read sub-account', async () => {
+ // List sub-accounts
+ const subAccountResponse = await billingTestHelper.userService.billingApi.readSubAccount('62978713f146ea8cb3bf8a95');
+ expect(subAccountResponse.status).to.be.eq(StatusCodes.FORBIDDEN);
+ });
});
});

doc(subaccounts): getOne/getMany endpoints doc