OCN Tutorial v1.1 incl. a billing service
The OCN tutorial must be brought on a next level to also showcase the power of the OCN Service Interface. The idea is that a mock billing service is created and used by the mock CPO and mock eMSP. Following set-up is proposed:
- Mock eMSP is set up and connected to own Node as well as registered at the Registry
- Mock CPO is set up and connected to own Node as well as registered at the Registry
- Billing Service is set up and connected to own Node as well as registered at the Registry
- Billing Service has the Credentials CH BIL
- Billing Service defines Permission 8 as required (https://bitbucket.org/shareandcharge/ocn-registry/src/d7f22574b1c7328fb0fabb55068b8c1ffdc9e0ea/Permissions.md?at=feature%2Ffix-permission-contract)
- Mock CPO signed up for this Permission
- Billing Service takes a random CDR which is sent from CPO to eMSP and creates an invoice
- Billing Service sends an invoice to the eMSP via a custom OCPI module
Comments (17)
-
-
- changed status to open
-
reporter -
assigned issue to
-
assigned issue to
-
@Christopher Burgahn Could I confirm the permissions configuration for this scenario with you? Permission 7 is to forward all OCPI requests of the cdrs module which are sent from an OCPI Party. But the “Sender” OCPI Interface for the CDRs module only defines a “GET” method. The method to send a new CDR is the “POST” method on the “Receiver” CDRs OCPI Interface. Is meaning of “SENDER” in “FORWARD_MODULE_CDRS_SENDER” different from the meaning “Sender” in the context of the Sender Inteface in the OCPI CDRs module?
@Adam Staveley @Arzon Barua Does the distinction above make sense to you? The way that the service interface request forwarding is setup in the ocn-node, it seems to use the Module and InterfaceRole when deciding if a request should be forwarded, see the
forwardOcpiRequestToLinkedServices
in AsyncTaskService below.In the case of the CDRs for example, the interfaceRole is RECEIVER (as per OCPI) when sending a CDR (see CdrsController below). I have found that I need to use permission “8” to get a request to this PostMapping to be forwarded. Is this what you would expect?
Snippet from AsyncTaskService: (https://bitbucket.org/shareandcharge/ocn-node/src/63fc9fb74362bd3bc0a90db4245ae1977c033a1d/src/main/kotlin/snc/openchargingnetwork/node/services/AsyncTaskService.kt)
/** * Finds all services, linked to a sender, with permissions that grant them access to a given request type. * Once services have been found, sends via provided request handler. */ @Async fun forwardOcpiRequestToLinkedServices(requestHandler: OcpiRequestHandler<*>, fromLocalPlatform: Boolean = true) { // we only want to forward to services if the module is one of the default OCPI modules, // and only if the sender is a local platform (to avoid repeat forwarding on the recipient node) // and also forward if service interface option is enabled val isDefaultModule = requestHandler.request.module != ModuleID.CUSTOM if (isDefaultModule && fromLocalPlatform && properties.serviceInterfaceEnabled) { val request = requestHandler.request registryService.getAgreementsByInterface(request.headers.sender, request.module, request.interfaceRole) .forEach { try { requestHandler.forwardAgain(it.provider) } catch (e: Exception) { // fire and forget logger.warn("Error forwarding request to service ${it.provider}: ${e.message}") } } } }
Snippet from CdrsController: (https://bitbucket.org/shareandcharge/ocn-node/src/63fc9fb74362bd3bc0a90db4245ae1977c033a1d/src/main/kotlin/snc/openchargingnetwork/node/controllers/ocpi/v2_2/CdrsController.kt)
@PostMapping("/ocpi/receiver/2.2/cdrs") fun postClientOwnedCdr(@RequestHeader("authorization") authorization: String, @RequestHeader("OCN-Signature") signature: String? = null, @RequestHeader("X-Request-ID") requestID: String, @RequestHeader("X-Correlation-ID") correlationID: String, @RequestHeader("OCPI-from-country-code") fromCountryCode: String, @RequestHeader("OCPI-from-party-id") fromPartyID: String, @RequestHeader("OCPI-to-country-code") toCountryCode: String, @RequestHeader("OCPI-to-party-id") toPartyID: String, @RequestBody body: CDR): ResponseEntity<OcpiResponse<Unit>> { val sender = BasicRole(fromPartyID, fromCountryCode) val receiver = BasicRole(toPartyID, toCountryCode) val requestVariables = OcpiRequestVariables( module = ModuleID.CDRS, interfaceRole = InterfaceRole.RECEIVER, method = HttpMethod.POST, headers = OcnHeaders(authorization, signature, requestID, correlationID, sender, receiver), body = body) return requestHandlerBuilder .build<Unit>(requestVariables) .forwardDefault() .getResponseWithLocationHeader("/ocpi/receiver/2.2/cdrs") }
-
reporter @John Henderson Thanks for this. I agree with you that we should follow the OCPI description of interfaces to not confuse people. The description of the permissions is currently slightly confusing. But @Adam Staveley
@Adam Staveley
or @Arzon Barua should confirm this.
Following this argumentation I’d say that there is a mistake in the description of this use-case.
This is what would change in the use-case:- Billing Service defines Permission 8 as required
I’m wondering whether we should change the description of the permissions slightly to make clear that we follow the interface descriptions of OCPI e.g. in this case:
Permission 8 FORWARD_MODULE_CDRS_RECEIVER OCN Node forwards all OCPI requests of the cdrs module which are sent to the receiver interface of an OCPI Party
-
@John Henderson “ it seems to use the Module and InterfaceRole when deciding if a request should be forwarded, see the
forwardOcpiRequestToLinkedServices
“ Yes you are right, we are checking the module ID and interface role to check the permission. You can also find the all permission checking in the following url
https://bitbucket.org/shareandcharge/ocn-node/src/develop/src/main/kotlin/snc/openchargingnetwork/node/models/Ocn.kt
enum class OcnServicePermission(val matches: (request: BasicRequestType) -> Boolean) { FORWARD_ALL({true}), FORWARD_ALL_SENDER({it.interfaceRole == InterfaceRole.SENDER}), FORWARD_ALL_RECEIVER({it.interfaceRole == InterfaceRole.RECEIVER}), FORWARD_MODULE_LOCATIONS_SENDER({it.moduleID == ModuleID.LOCATIONS && it.interfaceRole == InterfaceRole.SENDER}), FORWARD_MODULE_LOCATIONS_RECEIVER({it.moduleID == ModuleID.LOCATIONS && it.interfaceRole == InterfaceRole.RECEIVER}), FORWARD_MODULE_SESSIONS_SENDER({it.moduleID == ModuleID.SESSIONS && it.interfaceRole == InterfaceRole.SENDER}), FORWARD_MODULE_SESSIONS_RECEIVER({it.moduleID == ModuleID.SESSIONS && it.interfaceRole == InterfaceRole.RECEIVER }), FORWARD_MODULE_CDRS_SENDER({it.moduleID == ModuleID.CDRS && it.interfaceRole == InterfaceRole.SENDER}), FORWARD_MODULE_CDRS_RECEIVER({it.moduleID == ModuleID.CDRS && it.interfaceRole == InterfaceRole.RECEIVER}), FORWARD_MODULE_TARIFFS_SENDER({it.moduleID == ModuleID.TARIFFS && it.interfaceRole == InterfaceRole.SENDER}), FORWARD_MODULE_TARIFFS_RECEIVER({it.moduleID == ModuleID.TARIFFS && it.interfaceRole == InterfaceRole.RECEIVER}), FORWARD_MODULE_TOKENS_SENDER({it.moduleID == ModuleID.TOKENS && it.interfaceRole == InterfaceRole.SENDER}), FORWARD_MODULE_TOKENS_RECEIVER({it.moduleID == ModuleID.TOKENS && it.interfaceRole == InterfaceRole.RECEIVER}), FORWARD_MODULE_COMMANDS_SENDER({it.moduleID == ModuleID.COMMANDS && it.interfaceRole == InterfaceRole.SENDER}), FORWARD_MODULE_COMMANDS_RECEIVER({it.moduleID == ModuleID.COMMANDS && it.interfaceRole == InterfaceRole.RECEIVER}), FORWARD_MODULE_CHARGINGPROFILES_SENDER({it.moduleID == ModuleID.CHARGING_PROFILES && it.interfaceRole == InterfaceRole.SENDER}), FORWARD_MODULE_CHARGINGPROFILES_RECEIVER({it.moduleID == ModuleID.CHARGING_PROFILES && it.interfaceRole == InterfaceRole.RECEIVER}); companion object { fun getByIndex(index: BigInteger): OcnServicePermission? { return try { values()[index.intValueExact()] } catch (e: ArrayIndexOutOfBoundsException) { null } } } }
-
Thanks for the confirmation @Arzon Barua . I will proceed with the implementation of this demo scenario using the FORWARD_MODULE_CDRS_RECEIVER permission. @Christopher Burgahn I agree that we should change the permission descriptions as you described:
Permission 8 FORWARD_MODULE_CDRS_RECEIVER OCN Node forwards all OCPI requests of the cdrs module which are sent to the receiver interface of an OCPI Party
-
- edited description
-
@Christopher Burgahn Sorry, after thinking about it a bit more, I think a wording like this might be more accurate:
Permission 8 FORWARD_MODULE_CDRS_RECEIVER OCN Node forwards all OCPI requests sent by a party to the receiver interface of the cdrs module
This is because the OCPI party which needs to accept the permissions is the party which is sending the request and so I think the sending party should be the one that is mentioned in the description.
-
Sounds good to me. I think it will give more clear thought to the readers.
-
reporter Sounds good. I’ll create an issue on the ocn-registry repository for this change.
-
Currently blocked by: https://bitbucket.org/shareandcharge/ocn-node/issues/18/cannot-do-custom-module-post as ability to do a custom-module POST/PUT is required
-
Continuing with work on this using the ocn-node:bug/custom-module-post branch for the ocn-node.
@Christopher Burgahn Question for you when you have a moment: When the BillingService receives the forwarded CDR, how does it know the countryCode/partyID of the MSP to bill?
I am considering putting the MSP information in the “remark” field of the CDR, does that seem appropriate to you?
-
reporter @John Henderson good question. Remark field is a good option, also the CdrToken class contains some properties that are helpful with this, e.g. uid of the token, that could be used to identify the MSP to which the invoice is sent to. We can just use any of those options, as a billing service would have to decide by themselves how to do it.
-
@Christopher Burgahn Would you consider the billing service to have the “SCSP” OCPI role?
-
reporter @John Henderson I’d propose that the billing service has the role “OTHER” (https://github.com/ocpi/ocpi/blob/master/types.asciidoc#151-role-enum)
-
- changed status to resolved
Implemented by PR #4
- Log in to comment
I have begun work on this