From 75976c69f93810a070f95a4c2c77b68f11246ce4 Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Fri, 2 Sep 2022 13:09:11 +0200 Subject: [PATCH 01/16] Initial dir structure --- api/customer.yaml | 1282 +++++++++++++++++ .../fiware/tmforum/customer/Application.java | 31 + customer/src/main/resources/application.yaml | 44 + customer/src/main/resources/logback.xml | 16 + customer/src/test/resources/application.yaml | 38 + customer/src/test/resources/logback.xml | 16 + pom.xml | 1 + 7 files changed, 1428 insertions(+) create mode 100644 api/customer.yaml create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/Application.java create mode 100644 customer/src/main/resources/application.yaml create mode 100644 customer/src/main/resources/logback.xml create mode 100644 customer/src/test/resources/application.yaml create mode 100644 customer/src/test/resources/logback.xml diff --git a/api/customer.yaml b/api/customer.yaml new file mode 100644 index 00000000..b066d84e --- /dev/null +++ b/api/customer.yaml @@ -0,0 +1,1282 @@ +swagger: '2.0' +info: + title: Customer Management + description: This is Swagger UI environment generated for the TMF Customer Management specification + version: '4.0' +host: serverRoot +basePath: /tmf-api/customerManagement/v4/ +schemes: + - https +consumes: + - application/json;charset=utf-8 +produces: + - application/json;charset=utf-8 +tags: + - name: customer + - name: notification listeners (client side) + - name: events subscription +paths: + /customer: + get: + operationId: listCustomer + summary: List or find Customer objects + description: This operation list or find Customer entities + tags: + - customer + parameters: + - name: fields + description: Comma-separated properties to be provided in response + required: false + in: query + type: string + - name: offset + description: Requested index for start of resources to be provided in response + required: false + in: query + type: integer + - name: limit + description: Requested number of resources to be provided in response + required: false + in: query + type: integer + responses: + '200': + description: Success + headers: + X-Result-Count: + description: Actual number of items returned in the response body + type: integer + X-Total-Count: + description: Total number of items matching criteria + type: integer + schema: + type: array + items: + $ref: '#/definitions/Customer' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + post: + operationId: createCustomer + summary: Creates a Customer + description: This operation creates a Customer entity. + tags: + - customer + parameters: + - name: customer + description: The Customer to be created + required: true + schema: + $ref: '#/definitions/Customer_Create' + in: body + responses: + '201': + description: Created + schema: + $ref: '#/definitions/Customer' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /customer/{id}: + get: + operationId: retrieveCustomer + summary: Retrieves a Customer by ID + description: This operation retrieves a Customer entity. Attribute selection is enabled for all first level attributes. + tags: + - customer + parameters: + - name: id + description: Identifier of the Customer + required: true + type: string + in: path + - name: fields + description: Comma-separated properties to provide in response + required: false + type: string + in: query + responses: + '200': + description: Success + schema: + $ref: '#/definitions/Customer' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + patch: + operationId: patchCustomer + summary: Updates partially a Customer + description: This operation updates partially a Customer entity. + tags: + - customer + parameters: + - name: id + description: Identifier of the Customer + required: true + type: string + in: path + - name: customer + description: The Customer to be updated + required: true + schema: + $ref: '#/definitions/Customer_Update' + in: body + responses: + '200': + description: Updated + schema: + $ref: '#/definitions/Customer' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + delete: + operationId: deleteCustomer + summary: Deletes a Customer + description: This operation deletes a Customer entity. + tags: + - customer + parameters: + - name: id + description: Identifier of the Customer + required: true + type: string + in: path + responses: + '204': + description: Deleted + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /hub: + post: + operationId: registerListener + summary: Register a listener + description: Sets the communication endpoint address the service instance must use to deliver information about its health state, execution state, failures and metrics. + tags: + - events subscription + parameters: + - name: data + schema: + $ref: '#/definitions/EventSubscriptionInput' + required: true + in: body + description: Data containing the callback endpoint to deliver the information + responses: + '201': + description: Subscribed + schema: + $ref: '#/definitions/EventSubscription' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /hub/{id}: + delete: + operationId: unregisterListener + summary: Unregister a listener + description: Resets the communication endpoint address the service instance must use to deliver information about its health state, execution state, failures and metrics. + tags: + - events subscription + parameters: + - name: id + type: string + required: true + in: path + description: The id of the registered listener + responses: + '204': + description: Deleted + '400': + description: Bad request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method not allowed + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /listener/customerCreateEvent: + post: + operationId: listenToCustomerCreateEvent + summary: Client listener for entity CustomerCreateEvent + description: Example of a client listener for receiving the notification CustomerCreateEvent + tags: + - notification listeners (client side) + parameters: + - name: data + required: true + in: body + description: The event data + schema: + $ref: '#/definitions/CustomerCreateEvent' + responses: + '201': + description: Notified + schema: + $ref: '#/definitions/EventSubscription' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /listener/customerAttributeValueChangeEvent: + post: + operationId: listenToCustomerAttributeValueChangeEvent + summary: Client listener for entity CustomerAttributeValueChangeEvent + description: Example of a client listener for receiving the notification CustomerAttributeValueChangeEvent + tags: + - notification listeners (client side) + parameters: + - name: data + required: true + in: body + description: The event data + schema: + $ref: '#/definitions/CustomerAttributeValueChangeEvent' + responses: + '201': + description: Notified + schema: + $ref: '#/definitions/EventSubscription' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /listener/customerStateChangeEvent: + post: + operationId: listenToCustomerStateChangeEvent + summary: Client listener for entity CustomerStateChangeEvent + description: Example of a client listener for receiving the notification CustomerStateChangeEvent + tags: + - notification listeners (client side) + parameters: + - name: data + required: true + in: body + description: The event data + schema: + $ref: '#/definitions/CustomerStateChangeEvent' + responses: + '201': + description: Notified + schema: + $ref: '#/definitions/EventSubscription' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /listener/customerDeleteEvent: + post: + operationId: listenToCustomerDeleteEvent + summary: Client listener for entity CustomerDeleteEvent + description: Example of a client listener for receiving the notification CustomerDeleteEvent + tags: + - notification listeners (client side) + parameters: + - name: data + required: true + in: body + description: The event data + schema: + $ref: '#/definitions/CustomerDeleteEvent' + responses: + '201': + description: Notified + schema: + $ref: '#/definitions/EventSubscription' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' +definitions: + AccountRef: + type: object + description: Account reference. A account may be a party account or a financial account. + required: + - name + properties: + id: + type: string + description: Unique identifier of the account + href: + type: string + description: Reference of the account + description: + type: string + description: Detailed description of the account + name: + type: string + description: Name of the account + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + AgreementRef: + type: object + description: Agreement reference. An agreement represents a contract or arrangement, either written or verbal and sometimes enforceable by law, such as a service level agreement or a customer price agreement. An agreement involves a number of other business entities, such as products, services, and resources and/or their specifications. + properties: + id: + type: string + description: Unique identifier of a related entity. + href: + type: string + description: Reference of the related entity. + name: + type: string + description: Name of the agreement + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + Any: {} + Characteristic: + type: object + description: Describes a given characteristic of an object or entity through a name/value pair. + required: + - name + - value + properties: + name: + type: string + description: Name of the characteristic + valueType: + type: string + description: Data type of the value of the characteristic + value: + $ref: '#/definitions/Any' + description: The value of the characteristic + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + ContactMedium: + type: object + description: Indicates the contact medium that could be used to contact the party. + required: + - mediumType + - characteristic + properties: + mediumType: + type: string + description: 'Type of the contact medium, such as: email address, telephone number, postal address' + preferred: + type: boolean + description: If true, indicates that is the preferred contact medium + characteristic: + $ref: '#/definitions/MediumCharacteristic' + description: Any additional characteristic(s) of this contact medium + validFor: + $ref: '#/definitions/TimePeriod' + description: The time period that the contact medium is valid for + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + CreditProfile: + type: object + description: Credit profile for the party (containing credit scoring, ...). By default only the current credit profile is retrieved. It can be used as a list to give the party credit profiles history, the first one in the list will be the current one. + required: + - creditProfileDate + - validFor + properties: + creditProfileDate: + type: string + format: date-time + description: The date the profile was established + creditRiskRating: + type: integer + description: This is an integer whose value is used to rate the risk + creditScore: + type: integer + description: A measure of a person or organizations creditworthiness calculated on the basis of a combination of factors such as their income and credit history + validFor: + $ref: '#/definitions/TimePeriod' + description: The period for which the profile is valid + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + Customer: + type: object + required: + - engagedParty + properties: + id: + type: string + description: Unique identifier for Customers + href: + type: string + description: Url used to reference the customer. + name: + type: string + description: A word, term, or phrase by which the Customer is known and distinguished from other Customers. + status: + type: string + description: Used to track the lifecycle status of the customer. + statusReason: + type: string + description: A string providing an explanation on the value of the status lifecycle. For instance if the status is Rejected, statusReason will provide the reason for rejection. + account: + type: array + items: + $ref: '#/definitions/AccountRef' + agreement: + type: array + items: + $ref: '#/definitions/AgreementRef' + characteristic: + type: array + items: + $ref: '#/definitions/Characteristic' + description: Describes the characteristic of a customer. + contactMedium: + type: array + items: + $ref: '#/definitions/ContactMedium' + creditProfile: + type: array + items: + $ref: '#/definitions/CreditProfile' + engagedParty: + $ref: '#/definitions/RelatedParty' + description: The party - an organization or an individual - that is engaged as a customer. + paymentMethod: + type: array + items: + $ref: '#/definitions/PaymentMethodRef' + relatedParty: + type: array + items: + $ref: '#/definitions/RelatedParty' + validFor: + $ref: '#/definitions/TimePeriod' + description: The time period that the Customer is valid for. + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + Customer_Create: + type: object + description: |- + + Skipped properties: id,href + required: + - engagedParty + - name + properties: + name: + type: string + description: A word, term, or phrase by which the Customer is known and distinguished from other Customers. + status: + type: string + description: Used to track the lifecycle status of the customer. + statusReason: + type: string + description: A string providing an explanation on the value of the status lifecycle. For instance if the status is Rejected, statusReason will provide the reason for rejection. + account: + type: array + items: + $ref: '#/definitions/AccountRef' + agreement: + type: array + items: + $ref: '#/definitions/AgreementRef' + characteristic: + type: array + items: + $ref: '#/definitions/Characteristic' + description: Describes the characteristic of a customer. + contactMedium: + type: array + items: + $ref: '#/definitions/ContactMedium' + creditProfile: + type: array + items: + $ref: '#/definitions/CreditProfile' + engagedParty: + $ref: '#/definitions/RelatedParty' + description: The party - an organization or an individual - that is engaged as a customer. + paymentMethod: + type: array + items: + $ref: '#/definitions/PaymentMethodRef' + relatedParty: + type: array + items: + $ref: '#/definitions/RelatedParty' + validFor: + $ref: '#/definitions/TimePeriod' + description: The time period that the Customer is valid for. + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + Customer_Update: + type: object + description: |- + + Skipped properties: id,href + required: + - engagedParty + properties: + name: + type: string + description: A word, term, or phrase by which the Customer is known and distinguished from other Customers. + status: + type: string + description: Used to track the lifecycle status of the customer. + statusReason: + type: string + description: A string providing an explanation on the value of the status lifecycle. For instance if the status is Rejected, statusReason will provide the reason for rejection. + account: + type: array + items: + $ref: '#/definitions/AccountRef' + agreement: + type: array + items: + $ref: '#/definitions/AgreementRef' + characteristic: + type: array + items: + $ref: '#/definitions/Characteristic' + description: Describes the characteristic of a customer. + contactMedium: + type: array + items: + $ref: '#/definitions/ContactMedium' + creditProfile: + type: array + items: + $ref: '#/definitions/CreditProfile' + engagedParty: + $ref: '#/definitions/RelatedParty' + description: The party - an organization or an individual - that is engaged as a customer. + paymentMethod: + type: array + items: + $ref: '#/definitions/PaymentMethodRef' + relatedParty: + type: array + items: + $ref: '#/definitions/RelatedParty' + validFor: + $ref: '#/definitions/TimePeriod' + description: The time period that the Customer is valid for. + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + EntityRef: + type: object + description: Entity reference schema to be use for all entityRef class. + properties: + id: + type: string + description: Unique identifier of a related entity. + href: + type: string + description: Reference of the related entity. + name: + type: string + description: Name of the related entity. + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + MediumCharacteristic: + type: object + description: Describes the contact medium characteristics that could be used to contact a party (an individual or an organization) + properties: + city: + type: string + description: The city + contactType: + type: string + description: 'The type of contact, for example: phone number such as mobile, fixed home, fixed office. postal address such as shipping instalation…' + country: + type: string + description: The country + emailAddress: + type: string + description: Full email address in standard format + faxNumber: + type: string + description: The fax number of the contact + phoneNumber: + type: string + description: The primary phone number of the contact + postCode: + type: string + description: Postcode + socialNetworkId: + type: string + description: Identifier as a member of a social network + stateOrProvince: + type: string + description: State or province + street1: + type: string + description: Describes the street + street2: + type: string + description: Complementary street description + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + PaymentMethodRef: + type: object + description: PaymentMethod reference. A payment method defines a specific mean of payment (e.g direct debit). + properties: + id: + type: string + description: Unique identifier of the payment mean + href: + type: string + description: Reference of the payment mean + name: + type: string + description: Name of the payment mean + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + RelatedParty: + type: object + description: Related Entity reference. A related party defines party or party role linked to a specific entity. + required: + - '@referredType' + - id + properties: + id: + type: string + description: Unique identifier of a related entity. + href: + type: string + description: Reference of the related entity. + name: + type: string + description: Name of the related entity. + role: + type: string + description: Role played by the related party + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + TimePeriod: + type: object + description: A period of time, either as a deadline (endDateTime only) a startDateTime only, or both + properties: + endDateTime: + type: string + format: date-time + description: End of the time period, using IETC-RFC-3339 format + startDateTime: + type: string + format: date-time + description: Start of the time period, using IETC-RFC-3339 format. If you define a start, you must also define an end + EventSubscription: + type: object + description: Sets the communication endpoint address the service instance must use to deliver notification information + required: + - id + - callback + properties: + id: + type: string + description: Id of the listener + callback: + type: string + description: The callback being registered. + query: + type: string + description: additional data to be passed + EventSubscriptionInput: + type: object + description: Sets the communication endpoint address the service instance must use to deliver notification information + required: + - callback + properties: + callback: + type: string + description: The callback being registered. + query: + type: string + description: additional data to be passed + CustomerCreateEvent: + type: object + description: The notification data structure + properties: + id: + type: string + description: Identifier of the resource involved in the event + href: + type: string + description: Reference of the resource involved in the event + eventId: + type: string + description: The identifier of the notification. + eventTime: + type: string + format: date-time + description: Time of the event occurrence. + eventType: + type: string + description: The type of the notification. + correlationId: + type: string + description: The correlation id for this event. + domain: + type: string + description: The domain of the event. + title: + type: string + description: The title of the event. + description: + type: string + description: An explanatory of the event. + priority: + type: string + description: A priority. + timeOcurred: + type: string + format: date-time + description: The time the event occured. + event: + description: The event payload linked to the involved resource object + $ref: '#/definitions/CustomerCreateEventPayload' + CustomerCreateEventPayload: + type: object + description: The event data structure + properties: + customer: + description: The involved resource data for the event + $ref: '#/definitions/Customer' + CustomerAttributeValueChangeEvent: + type: object + description: The notification data structure + properties: + eventId: + type: string + description: The identifier of the notification. + eventTime: + type: string + format: date-time + description: Time of the event occurrence. + eventType: + type: string + description: The type of the notification. + correlationId: + type: string + description: The correlation id for this event. + domain: + type: string + description: The domain of the event. + title: + type: string + description: The title of the event. + description: + type: string + description: An explanatory of the event. + priority: + type: string + description: A priority. + timeOcurred: + type: string + format: date-time + description: The time the event occured. + fieldPath: + type: string + description: The path identifying the object field concerned by this notification. + event: + description: The event payload linked to the involved resource object + $ref: '#/definitions/CustomerAttributeValueChangeEventPayload' + CustomerAttributeValueChangeEventPayload: + type: object + description: The event data structure + properties: + customer: + description: The involved resource data for the event + $ref: '#/definitions/Customer' + CustomerStateChangeEvent: + type: object + description: The notification data structure + properties: + id: + type: string + description: Identifier of the resource involved in the event + href: + type: string + description: Reference of the resource involved in the event + eventId: + type: string + description: The identifier of the notification. + eventTime: + type: string + format: date-time + description: Time of the event occurrence. + eventType: + type: string + description: The type of the notification. + correlationId: + type: string + description: The correlation id for this event. + domain: + type: string + description: The domain of the event. + title: + type: string + description: The title of the event. + description: + type: string + description: An explanatory of the event. + priority: + type: string + description: A priority. + timeOcurred: + type: string + format: date-time + description: The time the event occured. + event: + description: The event payload linked to the involved resource object + $ref: '#/definitions/CustomerStateChangeEventPayload' + CustomerStateChangeEventPayload: + type: object + description: The event data structure + properties: + customer: + description: The involved resource data for the event + $ref: '#/definitions/Customer' + CustomerDeleteEvent: + type: object + description: The notification data structure + properties: + id: + type: string + description: Identifier of the resource involved in the event + href: + type: string + description: Reference of the resource involved in the event + eventId: + type: string + description: The identifier of the notification. + eventTime: + type: string + format: date-time + description: Time of the event occurrence. + eventType: + type: string + description: The type of the notification. + correlationId: + type: string + description: The correlation id for this event. + domain: + type: string + description: The domain of the event. + title: + type: string + description: The title of the event. + description: + type: string + description: An explanatory of the event. + priority: + type: string + description: A priority. + timeOcurred: + type: string + format: date-time + description: The time the event occured. + event: + description: The event payload linked to the involved resource object + $ref: '#/definitions/CustomerDeleteEventPayload' + CustomerDeleteEventPayload: + type: object + description: The event data structure + properties: + customer: + description: The involved resource data for the event + $ref: '#/definitions/Customer' + Error: + description: Used when an API throws an Error, typically with a HTTP error response-code (3xx, 4xx, 5xx) + type: object + required: + - code + - reason + properties: + code: + type: string + description: Application relevant detail, defined in the API or a common list. + reason: + type: string + description: Explanation of the reason for the error which can be shown to a client user. + message: + type: string + description: More details and corrective actions related to the error which can be shown to a client user. + status: + type: string + description: HTTP Error code extension + referenceError: + type: string + format: uri + description: URI of documentation describing the error. + '@baseType': + type: string + description: When sub-classing, this defines the super-class. + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name. diff --git a/customer/src/main/java/org/fiware/tmforum/customer/Application.java b/customer/src/main/java/org/fiware/tmforum/customer/Application.java new file mode 100644 index 00000000..c551de93 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/Application.java @@ -0,0 +1,31 @@ +package org.fiware.tmforum.customer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.micronaut.context.annotation.Bean; +import io.micronaut.context.annotation.Factory; +import io.micronaut.runtime.Micronaut; +import org.fiware.tmforum.mapping.EntitiesRepository; +import org.fiware.tmforum.mapping.EntityVOMapper; +import org.fiware.tmforum.mapping.JavaObjectMapper; + +/** + * Base application as starting point + */ +@Factory +public class Application { + + public static void main(String[] args) { + Micronaut.run(Application.class, args); + } + + @Bean + public EntityVOMapper entityVOMapper(ObjectMapper objectMapper, EntitiesRepository entitiesRepository) { + return new EntityVOMapper(objectMapper, entitiesRepository); + } + + @Bean + public JavaObjectMapper javaObjectMapper(ObjectMapper objectMapper) { + return new JavaObjectMapper(); + } + +} \ No newline at end of file diff --git a/customer/src/main/resources/application.yaml b/customer/src/main/resources/application.yaml new file mode 100644 index 00000000..0affe880 --- /dev/null +++ b/customer/src/main/resources/application.yaml @@ -0,0 +1,44 @@ +micronaut: + application: + name: ${project.artifactId} + + caches: + entities: + maximumSize: 1000 + + server: + port: 8080 + + metrics: + enabled: true + export: + prometheus: + step: PT2s + descriptions: false + + http: + services: + read-timeout: 30s + ngsi: + path: ngsi-ld/v1 + url: http://localhost:1026 + read-timeout: 30 +--- +jackson: + serialization: + writeDatesAsTimestamps: false +--- +endpoints: + metrics: + enabled: true + health: + enabled: true + +--- +loggers: + levels: + ROOT: TRACE + +--- +general: + contextUrl: https://smartdatamodels.org/context.jsonld \ No newline at end of file diff --git a/customer/src/main/resources/logback.xml b/customer/src/main/resources/logback.xml new file mode 100644 index 00000000..f075e861 --- /dev/null +++ b/customer/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + true + + + %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n + + + + + + + + \ No newline at end of file diff --git a/customer/src/test/resources/application.yaml b/customer/src/test/resources/application.yaml new file mode 100644 index 00000000..52f52f3f --- /dev/null +++ b/customer/src/test/resources/application.yaml @@ -0,0 +1,38 @@ +micronaut: + caches: + entities: + maximumSize: 1000 + + metrics: + enabled: false + export: + prometheus: + step: PT2s + descriptions: false + + http: + services: + read-timeout: 30s + ngsi: + path: ngsi-ld/v1 + url: http://localhost:1026 + read-timeout: 30 +--- +jackson: + serialization: + writeDatesAsTimestamps: false +--- +endpoints: + metrics: + enabled: false + health: + enabled: false + +--- +loggers: + levels: + ROOT: TRACE + +--- +general: + contextUrl: https://smartdatamodels.org/context.jsonld \ No newline at end of file diff --git a/customer/src/test/resources/logback.xml b/customer/src/test/resources/logback.xml new file mode 100644 index 00000000..f075e861 --- /dev/null +++ b/customer/src/test/resources/logback.xml @@ -0,0 +1,16 @@ + + + + true + + + %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index e9cf4911..10e74876 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,7 @@ mapping common party + customer From 95b8e84617c823c4043af925225e2a7873555ede Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Fri, 2 Sep 2022 13:10:07 +0200 Subject: [PATCH 02/16] Adding API pom --- customer/pom.xml | 257 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 257 insertions(+) create mode 100644 customer/pom.xml diff --git a/customer/pom.xml b/customer/pom.xml new file mode 100644 index 00000000..0c7feb87 --- /dev/null +++ b/customer/pom.xml @@ -0,0 +1,257 @@ + + + 4.0.0 + org.fiware.tmforum + customer + 0.1 + + + org.fiware + tmforum + 0.1 + + + + + org.fiware.tmforum + common + ${project.version} + compile + + + org.fiware.tmforum + mapping + ${project.version} + compile + + + + + org.projectlombok + lombok + + + org.mapstruct + mapstruct + + + + + io.micronaut + micronaut-inject + compile + + + io.micronaut + micronaut-validation + compile + + + io.micronaut + micronaut-runtime + compile + + + io.micronaut + micronaut-management + compile + + + io.micronaut.cache + micronaut-cache-caffeine + compile + + + io.micronaut + micronaut-http-client + compile + + + io.micronaut + micronaut-http-server-netty + compile + + + io.micronaut + micronaut-jackson-databind + compile + + + io.micronaut.rxjava2 + micronaut-rxjava2 + compile + + + io.micronaut + micronaut-jackson-core + compile + + + io.kokuwa.micronaut + micronaut-logging + ${version.io.kokuwa.micronaut.logging} + compile + + + + + javax.inject + javax.inject + + + javax.annotation + javax.annotation-api + + + + com.google.code.findbugs + annotations + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + compile + + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.jupiter + junit-jupiter-params + test + + + io.micronaut.test + micronaut-test-junit5 + test + + + io.micronaut.test + micronaut-test-core + test + + + + org.mockito + mockito-all + test + + + org.mockito + mockito-junit-jupiter + test + + + org.awaitility + awaitility + test + + + + + + + src/main/resources + true + + + src/test/resources + true + + + + + + org.openapitools + openapi-generator-maven-plugin + ${version.org.openapitools.generator-maven-plugin} + + + openapi-customer-api + generate-sources + + generate + + + ${project.parent.basedir}/api/customer.yaml + org.fiware.customer.api + true + org.fiware.customer.model + true + micronaut + false + false + VO + ${project.build.directory} + + true + false + true + true + true + false + true + false + true + + + java.util.Date=java.time.Instant + + + + + + + io.kokuwa.micronaut + micronaut-openapi-codegen + ${version.io.kokuwa.micronaut.codegen} + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + io.kokuwa.maven + k3s-maven-plugin + + + + + com.google.cloud.tools + jib-maven-plugin + + + + \ No newline at end of file From 94ca10f54dfdcd40d41fd7b1a4387da0530aa38b Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Fri, 2 Sep 2022 15:29:48 +0200 Subject: [PATCH 03/16] Adding mappings for some first attributes. Adding test. --- .../tmforum/customer/TMForumMapper.java | 81 +++++++++++++++++++ .../customer/domain/ContactMedium.java | 16 ++++ .../customer/domain/MediumCharacteristic.java | 23 ++++++ .../tmforum/customer/domain/RefEntity.java | 38 +++++++++ .../tmforum/customer/domain/RelatedParty.java | 33 ++++++++ .../tmforum/customer/domain/TimePeriod.java | 13 +++ .../customer/domain/customer/Customer.java | 67 +++++++++++++++ .../exception/CustomerCreationException.java | 15 ++++ .../repository/CustomerRepository.java | 27 +++++++ .../customer/rest/CustomerApiController.java | 76 +++++++++++++++++ .../tmforum/customer/CustomerApiIT.java | 76 +++++++++++++++++ 11 files changed, 465 insertions(+) create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/domain/ContactMedium.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/domain/MediumCharacteristic.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/domain/RefEntity.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/domain/RelatedParty.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/domain/TimePeriod.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerCreationException.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java create mode 100644 customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java diff --git a/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java b/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java new file mode 100644 index 00000000..ff4bf72d --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java @@ -0,0 +1,81 @@ +package org.fiware.tmforum.customer; + +import org.fiware.customer.model.*; +import org.fiware.tmforum.customer.domain.ContactMedium; +import org.fiware.tmforum.customer.domain.MediumCharacteristic; +import org.fiware.tmforum.customer.domain.TimePeriod; +import org.fiware.tmforum.customer.domain.customer.Customer; +import org.fiware.tmforum.mapping.MappingException; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; + +/** + * Mapper between the internal model and api-domain objects + */ +@Mapper(componentModel = "jsr330") +public interface TMForumMapper { + + String ID_TEMPLATE = "urn:ngsi-ld:%s:%s"; + + + // using inline expression, since else it might overwrite the String-String mapping + @Mapping(target = "id", expression = "java(java.lang.String.format(ID_TEMPLATE, \"customer\", java.util.UUID.randomUUID()))") + @Mapping(target = "href", ignore = true) + CustomerVO map(CustomerCreateVO customerCreateVO); + + CustomerVO map(Customer customer); + + Customer map(CustomerVO customerVO); + + @Mapping(source = "characteristic", target = "mediumCharacteristic") + ContactMedium map(ContactMediumVO contactMediumVO); + + @Mapping(target = "characteristic", source = "mediumCharacteristic") + @Mapping(target = "validFor", source = "validFor") + ContactMediumVO map(ContactMedium contactMedium); + + MediumCharacteristic map(MediumCharacteristicVO mediumCharacteristicVO); + + MediumCharacteristicVO map(MediumCharacteristic mediumCharacteristic); + + TimePeriodVO map(TimePeriod timePeriod); + + TimePeriod map(TimePeriodVO value); + + default URL map(String value) { + if (value == null) { + return null; + } + try { + return new URL(value); + } catch (MalformedURLException e) { + throw new MappingException(String.format("%s is not a URL.", value), e); + } + } + + default String map(URL value) { + if (value == null) { + return null; + } + return value.toString(); + } + + default URI mapToURI(String value) { + if (value == null) { + return null; + } + return URI.create(value); + } + + default String mapFromURI(URI value) { + if (value == null) { + return null; + } + return value.toString(); + } + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/ContactMedium.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/ContactMedium.java new file mode 100644 index 00000000..a18caccb --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/ContactMedium.java @@ -0,0 +1,16 @@ +package org.fiware.tmforum.customer.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +@Data +@EqualsAndHashCode(callSuper = true) +public class ContactMedium extends Entity { + + private String mediumType; + private boolean preferred; + private MediumCharacteristic mediumCharacteristic; + private TimePeriod validFor; + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/MediumCharacteristic.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/MediumCharacteristic.java new file mode 100644 index 00000000..5b7e1815 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/MediumCharacteristic.java @@ -0,0 +1,23 @@ +package org.fiware.tmforum.customer.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +@Data +@EqualsAndHashCode(callSuper = true) +public class MediumCharacteristic extends Entity { + + private String city; + private String contactType; + private String country; + private String emailAddress; + private String faxNumber; + private String phoneNumber; + private String postCode; + private String socialNetworkId; + private String stateOrProvince; + private String street1; + private String street2; + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/RefEntity.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/RefEntity.java new file mode 100644 index 00000000..267382b1 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/RefEntity.java @@ -0,0 +1,38 @@ +package org.fiware.tmforum.customer.domain; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.fiware.tmforum.common.domain.Entity; +import org.fiware.tmforum.common.validation.ReferencedEntity; +import org.fiware.tmforum.mapping.annotations.*; + +import java.net.URI; + +@EqualsAndHashCode +public abstract class RefEntity extends Entity implements ReferencedEntity { + + @Getter(onMethod = @__({@RelationshipObject, @DatasetId})) + final URI id; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "href")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "href")})) + private URI href; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "name")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name")})) + private String name; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "@referredType")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "@referredType")})) + private String atReferredType; + + protected RefEntity(String id) { + this.id = URI.create(id); + } + + protected RefEntity(URI id) { + this.id = id; + } + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/RelatedParty.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/RelatedParty.java new file mode 100644 index 00000000..fa292423 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/RelatedParty.java @@ -0,0 +1,33 @@ +package org.fiware.tmforum.customer.domain; + +import lombok.Getter; +import lombok.Setter; +import org.fiware.tmforum.customer.domain.customer.Customer; +import org.fiware.tmforum.mapping.annotations.AttributeGetter; +import org.fiware.tmforum.mapping.annotations.AttributeSetter; +import org.fiware.tmforum.mapping.annotations.AttributeType; +import org.fiware.tmforum.mapping.annotations.Ignore; + +import java.util.List; + +public class RelatedParty extends RefEntity { + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "name", embedProperty = true)})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name", targetClass = String.class)})) + private String name; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "role", embedProperty = true)})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "role", targetClass = String.class)})) + private String role; + + public RelatedParty(String id) { + super(id); + } + + @Override + @Ignore + public List getReferencedTypes() { + return List.of(Customer.TYPE_CUSTOMER); + } + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/TimePeriod.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/TimePeriod.java new file mode 100644 index 00000000..c78e972a --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/TimePeriod.java @@ -0,0 +1,13 @@ +package org.fiware.tmforum.customer.domain; + +import lombok.Data; + +import java.time.Instant; + +@Data +public class TimePeriod { + + private Instant endDateTime; + private Instant startDateTime; + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java new file mode 100644 index 00000000..5be40944 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java @@ -0,0 +1,67 @@ +package org.fiware.tmforum.customer.domain.customer; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.fiware.customer.model.RelatedPartyVO; +import org.fiware.tmforum.common.domain.EntityWithId; +import org.fiware.tmforum.customer.domain.ContactMedium; +import org.fiware.tmforum.customer.domain.RelatedParty; +import org.fiware.tmforum.mapping.annotations.AttributeGetter; +import org.fiware.tmforum.mapping.annotations.AttributeSetter; +import org.fiware.tmforum.mapping.annotations.AttributeType; +import org.fiware.tmforum.mapping.annotations.MappingEnabled; + +import java.net.URL; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@MappingEnabled(entityType = Customer.TYPE_CUSTOMER) +public class Customer extends EntityWithId { + + public static final String TYPE_CUSTOMER = "customer"; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "href")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "href")})) + private URL href; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "name")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name")})) + private String name; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "status")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "status")})) + private String status; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "statusReason")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "statusReason")})) + private String statusReason; + + // private java.util.List account; + + // private java.util.List agreement; + + // private java.util.List characteristic; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "contactMedium")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "contactMedium", targetClass = ContactMedium.class)})) + private List contactMedium; + + // private java.util.List creditProfile; + + // private RelatedPartyVO engagedParty; + + // private java.util.List paymentMethod; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "relatedParty")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "relatedParty", targetClass = RelatedParty.class, fromProperties = true)})) + private List relatedParty; + + // private TimePeriodVO validFor; + + + + public Customer(String id) { + super(TYPE_CUSTOMER, id); + } +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerCreationException.java b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerCreationException.java new file mode 100644 index 00000000..11c6f82d --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerCreationException.java @@ -0,0 +1,15 @@ +package org.fiware.tmforum.customer.exception; + +/** + * Exception to be thrown in case a customer could not have been created. + */ +public class CustomerCreationException extends RuntimeException { + + public CustomerCreationException(String message) { + super(message); + } + + public CustomerCreationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java b/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java new file mode 100644 index 00000000..93b44264 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java @@ -0,0 +1,27 @@ +package org.fiware.tmforum.customer.repository; + +import io.reactivex.Completable; +import org.fiware.ngsi.api.EntitiesApi; +import org.fiware.tmforum.common.configuration.GeneralProperties; +import org.fiware.tmforum.common.repository.NgsiLdBaseRepository; +import org.fiware.tmforum.customer.domain.customer.Customer; +import org.fiware.tmforum.mapping.EntityVOMapper; +import org.fiware.tmforum.mapping.JavaObjectMapper; + +public class CustomerRepository extends NgsiLdBaseRepository { + + private final EntityVOMapper entityVOMapper; + private final JavaObjectMapper javaObjectMapper; + + public CustomerRepository(GeneralProperties generalProperties, EntitiesApi entitiesApi, EntityVOMapper entityVOMapper, JavaObjectMapper javaObjectMapper) { + super(generalProperties, entitiesApi); + this.entityVOMapper = entityVOMapper; + this.javaObjectMapper = javaObjectMapper; + } + + public Completable createCustomer(Customer customer) { + return createEntity(javaObjectMapper.toEntityVO(customer), generalProperties.getTenant()); + } + + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java b/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java new file mode 100644 index 00000000..e0cce7e8 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java @@ -0,0 +1,76 @@ +package org.fiware.tmforum.customer.rest; + +import io.micronaut.http.HttpResponse; +import io.micronaut.http.annotation.Controller; +import io.reactivex.Single; +import io.reactivex.schedulers.Schedulers; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fiware.customer.api.CustomerApi; +import org.fiware.customer.model.CustomerCreateVO; +import org.fiware.customer.model.CustomerUpdateVO; +import org.fiware.customer.model.CustomerVO; +import org.fiware.tmforum.common.exception.NonExistentReferenceException; +import org.fiware.tmforum.common.validation.ReferenceValidationService; +import org.fiware.tmforum.customer.TMForumMapper; +import org.fiware.tmforum.customer.domain.customer.Customer; +import org.fiware.tmforum.customer.exception.CustomerCreationException; +import org.fiware.tmforum.customer.repository.CustomerRepository; + +import javax.annotation.Nullable; +import java.util.List; + +@Slf4j +@Controller +@RequiredArgsConstructor +public class CustomerApiController implements CustomerApi { + + private final TMForumMapper tmForumMapper; + private final CustomerRepository customerRepository; + private final ReferenceValidationService validationService; + + @Override + public Single> createCustomer(CustomerCreateVO customerCreateVO) { + CustomerVO customerVO = tmForumMapper.map(customerCreateVO); + Customer customer = tmForumMapper.map(customerVO); + + Single customerSingle = Single.just(customer); + Single checkingSingle; + + try { + if (customer.getRelatedParty() != null && !customer.getRelatedParty().isEmpty()) { + checkingSingle = validationService.getCheckingSingleOrThrow(customer.getRelatedParty(), customer); + customerSingle = Single.zip(customerSingle, checkingSingle, (p1, p2) -> p1); + } + } catch (NonExistentReferenceException e) { + throw new CustomerCreationException(String.format("Was not able to create customer %s", customer.getId()), e); + } + + return customerSingle + .flatMap(customerToCreate -> customerRepository.createCustomer(customerToCreate).toSingleDefault(customerToCreate)) + .cast(Customer.class) + .map(tmForumMapper::map) + .subscribeOn(Schedulers.io()) + .map(HttpResponse::created); + } + + @Override + public Single> deleteCustomer(String id) { + return null; + } + + @Override + public Single>> listCustomer(@Nullable String fields, @Nullable Integer offset, @Nullable Integer limit) { + return null; + } + + @Override + public Single> patchCustomer(String id, CustomerUpdateVO customer) { + return null; + } + + @Override + public Single> retrieveCustomer(String id, @Nullable String fields) { + return null; + } +} diff --git a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java new file mode 100644 index 00000000..6e51635b --- /dev/null +++ b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java @@ -0,0 +1,76 @@ +package org.fiware.tmforum.customer; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import lombok.RequiredArgsConstructor; +import org.fiware.customer.model.*; +import org.fiware.tmforum.customer.rest.CustomerApiController; +import org.junit.jupiter.api.Test; +import java.text.ParseException; +import java.time.Duration; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +@RequiredArgsConstructor +@MicronautTest(packages = {"org.fiware.tmforum.customer"}) +class CustomerApiIT { + + private final ObjectMapper objectMapper; + private final CustomerApiController customerApiController; + + @Test + void test() throws JsonProcessingException, ParseException { + CustomerCreateVO myFancyCustomerCreate = getMyFancyCustomer(); + + HttpResponse myFancyCustomerCreateResponse = customerApiController.createCustomer(myFancyCustomerCreate).blockingGet(); + assertEquals(HttpStatus.CREATED, myFancyCustomerCreateResponse.getStatus(), "Customer should have been created"); + CustomerVO myFancyCustomer = myFancyCustomerCreateResponse.body(); + } + + private CustomerCreateVO getMyFancyCustomer() throws JsonProcessingException { + + CustomerCreateVO customerVO = new CustomerCreateVO(); + customerVO.setName("My Fancy Customer"); + customerVO.setStatus("My fancy status"); + customerVO.setStatusReason("Fancy reason for my fancy status"); + + MediumCharacteristicVO mediumCharacteristicVO = new MediumCharacteristicVO(); + mediumCharacteristicVO.setCity("Berlin"); + mediumCharacteristicVO.setContactType("postal address"); + mediumCharacteristicVO.setCountry("Germany"); + mediumCharacteristicVO.setEmailAddress("my-fancy@company.org"); + mediumCharacteristicVO.setPhoneNumber("0123/4567890-0"); + mediumCharacteristicVO.setFaxNumber("0123/4567890-1"); + mediumCharacteristicVO.setPostCode("10719"); + mediumCharacteristicVO.setSocialNetworkId("@fancy"); + mediumCharacteristicVO.setStateOrProvince("Berlin"); + mediumCharacteristicVO.street1("Kurfürstendamm 12"); + + ContactMediumVO contactMediumVO = new ContactMediumVO(); + contactMediumVO.setMediumType("postal address"); + contactMediumVO.setPreferred(true); + contactMediumVO.setCharacteristic(mediumCharacteristicVO); + contactMediumVO.setValidFor(new TimePeriodVO().startDateTime(Instant.now()).endDateTime(Instant.now().plus(Duration.of(10, ChronoUnit.DAYS)))); + + customerVO.setContactMedium(List.of(contactMediumVO)); + + return customerVO; + } + + class TestCharacteristic { + public final long valuation; + public final String unit; + + TestCharacteristic(long valuation, String unit) { + this.valuation = valuation; + this.unit = unit; + } + } + +} \ No newline at end of file From bc9cb5cc5cffe74074c68db8968e40fff18e5ce0 Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Fri, 2 Sep 2022 15:35:00 +0200 Subject: [PATCH 04/16] Add RelatedParty to mapper --- .../main/java/org/fiware/tmforum/customer/TMForumMapper.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java b/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java index ff4bf72d..55779c5b 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java @@ -3,6 +3,7 @@ import org.fiware.customer.model.*; import org.fiware.tmforum.customer.domain.ContactMedium; import org.fiware.tmforum.customer.domain.MediumCharacteristic; +import org.fiware.tmforum.customer.domain.RelatedParty; import org.fiware.tmforum.customer.domain.TimePeriod; import org.fiware.tmforum.customer.domain.customer.Customer; import org.fiware.tmforum.mapping.MappingException; @@ -31,6 +32,10 @@ public interface TMForumMapper { Customer map(CustomerVO customerVO); + RelatedParty map(RelatedPartyVO relatedPartyVO); + + RelatedPartyVO map(RelatedParty relatedParty); + @Mapping(source = "characteristic", target = "mediumCharacteristic") ContactMedium map(ContactMediumVO contactMediumVO); From 3f4c963692abf8785113f14a7eb654f8bb593f99 Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Tue, 6 Sep 2022 09:26:46 +0200 Subject: [PATCH 05/16] Fix annotation --- .../fiware/tmforum/customer/repository/CustomerRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java b/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java index 93b44264..328741a1 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java @@ -8,6 +8,9 @@ import org.fiware.tmforum.mapping.EntityVOMapper; import org.fiware.tmforum.mapping.JavaObjectMapper; +import javax.inject.Singleton; + +@Singleton public class CustomerRepository extends NgsiLdBaseRepository { private final EntityVOMapper entityVOMapper; From ba9b6d5124c109479d1430fece5aa4309e2820c1 Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Tue, 6 Sep 2022 15:38:12 +0200 Subject: [PATCH 06/16] Adding remaining attributes and methods. --- .../tmforum/customer/TMForumMapper.java | 20 +++++++-- .../tmforum/customer/domain/AccountRef.java | 33 ++++++++++++++ .../tmforum/customer/domain/AgreementRef.java | 29 ++++++++++++ .../customer/domain/Characteristic.java | 15 +++++++ .../customer/domain/CreditProfile.java | 17 +++++++ .../customer/domain/PaymentMethodRef.java | 27 +++++++++++ .../customer/domain/customer/Customer.java | 33 +++++++++----- .../repository/CustomerRepository.java | 40 +++++++++++++++++ .../customer/rest/CustomerApiController.java | 13 ++++-- .../tmforum/customer/CustomerApiIT.java | 45 +++++++++++++++++++ 10 files changed, 254 insertions(+), 18 deletions(-) create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/domain/AccountRef.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/domain/AgreementRef.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/domain/Characteristic.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/domain/CreditProfile.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/domain/PaymentMethodRef.java diff --git a/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java b/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java index 55779c5b..c1784d46 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java @@ -1,10 +1,7 @@ package org.fiware.tmforum.customer; import org.fiware.customer.model.*; -import org.fiware.tmforum.customer.domain.ContactMedium; -import org.fiware.tmforum.customer.domain.MediumCharacteristic; -import org.fiware.tmforum.customer.domain.RelatedParty; -import org.fiware.tmforum.customer.domain.TimePeriod; +import org.fiware.tmforum.customer.domain.*; import org.fiware.tmforum.customer.domain.customer.Customer; import org.fiware.tmforum.mapping.MappingException; import org.mapstruct.Mapper; @@ -36,6 +33,21 @@ public interface TMForumMapper { RelatedPartyVO map(RelatedParty relatedParty); + AccountRef map(AccountRefVO accountRefVO); + AccountRefVO map(AccountRef accountRef); + + AgreementRef map(AgreementRefVO agreementRefVO); + AgreementRefVO map(AgreementRef agreementRef); + + CharacteristicVO map(Characteristic characteristic); + Characteristic map(CharacteristicVO characteristicVO); + + CreditProfileVO map(CreditProfile creditProfile); + CreditProfile map(CreditProfileVO creditProfileVO); + + PaymentMethodRef map(PaymentMethodRefVO paymentMethodRefVO); + PaymentMethodRefVO map(PaymentMethodRef paymentMethodRef); + @Mapping(source = "characteristic", target = "mediumCharacteristic") ContactMedium map(ContactMediumVO contactMediumVO); diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/AccountRef.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/AccountRef.java new file mode 100644 index 00000000..60303ad9 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/AccountRef.java @@ -0,0 +1,33 @@ +package org.fiware.tmforum.customer.domain; + +import lombok.Getter; +import lombok.Setter; +import org.fiware.tmforum.customer.domain.customer.Customer; +import org.fiware.tmforum.mapping.annotations.AttributeGetter; +import org.fiware.tmforum.mapping.annotations.AttributeSetter; +import org.fiware.tmforum.mapping.annotations.AttributeType; +import org.fiware.tmforum.mapping.annotations.Ignore; + +import java.util.List; + +public class AccountRef extends RefEntity { + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "name", embedProperty = true)})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name", targetClass = String.class)})) + private String name; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "description", embedProperty = true)})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "description", targetClass = String.class)})) + private String description; + + public AccountRef(String id) { + super(id); + } + + @Override + @Ignore + public List getReferencedTypes() { + return List.of(Customer.TYPE_CUSTOMER); + } + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/AgreementRef.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/AgreementRef.java new file mode 100644 index 00000000..42629d42 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/AgreementRef.java @@ -0,0 +1,29 @@ +package org.fiware.tmforum.customer.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.fiware.tmforum.common.domain.Entity; +import org.fiware.tmforum.customer.domain.customer.Customer; +import org.fiware.tmforum.mapping.annotations.AttributeGetter; +import org.fiware.tmforum.mapping.annotations.AttributeSetter; +import org.fiware.tmforum.mapping.annotations.AttributeType; + +import java.util.List; + +public class AgreementRef extends RefEntity { + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "name", embedProperty = true)})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name", targetClass = String.class)})) + private String name; + + public AgreementRef(String id) { + super(id); + } + + @Override + public List getReferencedTypes() { + return List.of(Customer.TYPE_CUSTOMER); + } +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/Characteristic.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/Characteristic.java new file mode 100644 index 00000000..59703ba6 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/Characteristic.java @@ -0,0 +1,15 @@ +package org.fiware.tmforum.customer.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +@Data +@EqualsAndHashCode(callSuper = true) +public class Characteristic extends Entity { + + private String name; + private String valueType; + private Object value; + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/CreditProfile.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/CreditProfile.java new file mode 100644 index 00000000..3df9bffa --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/CreditProfile.java @@ -0,0 +1,17 @@ +package org.fiware.tmforum.customer.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +import java.time.Instant; + +@Data +@EqualsAndHashCode(callSuper = true) +public class CreditProfile extends Entity { + + private Instant creditProfileDate; + private Integer creditRiskRating; + private Integer creditScore; + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/PaymentMethodRef.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/PaymentMethodRef.java new file mode 100644 index 00000000..b42d7360 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/PaymentMethodRef.java @@ -0,0 +1,27 @@ +package org.fiware.tmforum.customer.domain; + +import lombok.Getter; +import lombok.Setter; +import org.fiware.tmforum.customer.domain.customer.Customer; +import org.fiware.tmforum.mapping.annotations.AttributeGetter; +import org.fiware.tmforum.mapping.annotations.AttributeSetter; +import org.fiware.tmforum.mapping.annotations.AttributeType; + +import java.util.List; + +public class PaymentMethodRef extends RefEntity { + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "name", embedProperty = true)})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name", targetClass = String.class)})) + private String name; + + public PaymentMethodRef(String id) { + super(id); + } + + @Override + public List getReferencedTypes() { + return List.of(Customer.TYPE_CUSTOMER); + } + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java index 5be40944..9a4839ae 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java @@ -5,8 +5,7 @@ import lombok.Setter; import org.fiware.customer.model.RelatedPartyVO; import org.fiware.tmforum.common.domain.EntityWithId; -import org.fiware.tmforum.customer.domain.ContactMedium; -import org.fiware.tmforum.customer.domain.RelatedParty; +import org.fiware.tmforum.customer.domain.*; import org.fiware.tmforum.mapping.annotations.AttributeGetter; import org.fiware.tmforum.mapping.annotations.AttributeSetter; import org.fiware.tmforum.mapping.annotations.AttributeType; @@ -37,29 +36,41 @@ public class Customer extends EntityWithId { @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "statusReason")})) private String statusReason; - // private java.util.List account; + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "account")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "account", targetClass = AccountRef.class, fromProperties = true)})) + private List account; - // private java.util.List agreement; + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "agreement")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "agreement", targetClass = AgreementRef.class, fromProperties = true)})) + private List agreement; - // private java.util.List characteristic; + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "customerCharacteristic")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "customerCharacteristic", targetClass = Characteristic.class)})) + private List customerCharacteristic; @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "contactMedium")})) @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "contactMedium", targetClass = ContactMedium.class)})) private List contactMedium; - // private java.util.List creditProfile; + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "creditProfile")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "creditProfile", targetClass = CreditProfile.class)})) + private List creditProfile; - // private RelatedPartyVO engagedParty; + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.RELATIONSHIP, targetName = "engagedParty")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.RELATIONSHIP, targetName = "engagedParty", targetClass = RelatedParty.class, fromProperties = true)})) + private RelatedPartyVO engagedParty; - // private java.util.List paymentMethod; + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "paymentMethod")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "paymentMethod", targetClass = PaymentMethodRef.class, fromProperties = true)})) + private List paymentMethod; @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "relatedParty")})) @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "relatedParty", targetClass = RelatedParty.class, fromProperties = true)})) private List relatedParty; - // private TimePeriodVO validFor; - - + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "validFor")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "validFor", targetClass = TimePeriod.class)})) + private TimePeriod validFor; public Customer(String id) { super(TYPE_CUSTOMER, id); diff --git a/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java b/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java index 328741a1..53afc465 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java @@ -1,7 +1,10 @@ package org.fiware.tmforum.customer.repository; import io.reactivex.Completable; +import io.reactivex.Maybe; +import io.reactivex.Single; import org.fiware.ngsi.api.EntitiesApi; +import org.fiware.ngsi.model.EntityVO; import org.fiware.tmforum.common.configuration.GeneralProperties; import org.fiware.tmforum.common.repository.NgsiLdBaseRepository; import org.fiware.tmforum.customer.domain.customer.Customer; @@ -9,6 +12,10 @@ import org.fiware.tmforum.mapping.JavaObjectMapper; import javax.inject.Singleton; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; @Singleton public class CustomerRepository extends NgsiLdBaseRepository { @@ -26,5 +33,38 @@ public Completable createCustomer(Customer customer) { return createEntity(javaObjectMapper.toEntityVO(customer), generalProperties.getTenant()); } + public Completable deleteCustomer(String id) { + return entitiesApi.removeEntityById(URI.create(id), generalProperties.getTenant(), null); + } + + public Single> findCustomers() { + return entitiesApi.queryEntities(generalProperties.getTenant(), + null, + null, + Customer.TYPE_CUSTOMER, + null, + null, + null, + null, + null, + null, + null, + null, + null, + getLinkHeader()) + .map(List::stream) + .flatMap(entityVOStream -> zipToList(entityVOStream, Customer.class)); + } + public Maybe getCustomer(String id) { + return retrieveEntityById(URI.create(id)) + .flatMap(entityVO -> entityVOMapper.fromEntityVO(entityVO, Customer.class).toMaybe()); + } + + private Single> zipToList(Stream entityVOStream, Class targetClass) { + return Single.zip( + entityVOStream.map(entityVO -> entityVOMapper.fromEntityVO(entityVO, targetClass)).toList(), + oList -> Arrays.stream(oList).map(targetClass::cast).toList() + ); + } } diff --git a/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java b/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java index e0cce7e8..8387defc 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java @@ -56,21 +56,28 @@ public Single> createCustomer(CustomerCreateVO customer @Override public Single> deleteCustomer(String id) { - return null; + return customerRepository.deleteCustomer(id).toSingleDefault(HttpResponse.noContent()); } @Override public Single>> listCustomer(@Nullable String fields, @Nullable Integer offset, @Nullable Integer limit) { - return null; + return customerRepository.findCustomers() + .map(List::stream) + .map(customerStream -> customerStream.map(tmForumMapper::map).toList()) + .map(HttpResponse::ok); } @Override public Single> patchCustomer(String id, CustomerUpdateVO customer) { + // implement proper patch return null; } @Override public Single> retrieveCustomer(String id, @Nullable String fields) { - return null; + return customerRepository.getCustomer(id) + .map(tmForumMapper::map) + .toSingle() + .map(HttpResponse::ok); } } diff --git a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java index 6e51635b..1cb802f8 100644 --- a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java +++ b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java @@ -16,6 +16,7 @@ import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; @RequiredArgsConstructor @MicronautTest(packages = {"org.fiware.tmforum.customer"}) @@ -28,9 +29,21 @@ class CustomerApiIT { void test() throws JsonProcessingException, ParseException { CustomerCreateVO myFancyCustomerCreate = getMyFancyCustomer(); + // Test create HttpResponse myFancyCustomerCreateResponse = customerApiController.createCustomer(myFancyCustomerCreate).blockingGet(); assertEquals(HttpStatus.CREATED, myFancyCustomerCreateResponse.getStatus(), "Customer should have been created"); CustomerVO myFancyCustomer = myFancyCustomerCreateResponse.body(); + + // Test retrieve + HttpResponse customerVOHttpResponse = customerApiController.retrieveCustomer(myFancyCustomer.getId(), null).blockingGet(); + assertEquals(HttpStatus.OK, customerVOHttpResponse.getStatus(), "A customer response is expected."); + assertTrue(customerVOHttpResponse.getBody().isPresent(), "A customer response is expected."); + assertEquals(myFancyCustomer, customerVOHttpResponse.getBody().get(), "The full customer should be retrieved"); + + // Test delete + HttpResponse customerDeleteResponse = customerApiController.deleteCustomer(myFancyCustomer.getId()).blockingGet(); + assertEquals(HttpStatus.NO_CONTENT, customerDeleteResponse.getStatus(), "A NO_CONTENT response is expected"); + } private CustomerCreateVO getMyFancyCustomer() throws JsonProcessingException { @@ -58,7 +71,39 @@ private CustomerCreateVO getMyFancyCustomer() throws JsonProcessingException { contactMediumVO.setCharacteristic(mediumCharacteristicVO); contactMediumVO.setValidFor(new TimePeriodVO().startDateTime(Instant.now()).endDateTime(Instant.now().plus(Duration.of(10, ChronoUnit.DAYS)))); + AccountRefVO accountRefVO = new AccountRefVO(); + accountRefVO.setId("urn:ngsi-ld:AccountRef:MyAccountRef001"); + accountRefVO.setName("My AccountRef name"); + accountRefVO.setDescription("My AccountRef description"); + + AgreementRefVO agreementRefVO = new AgreementRefVO(); + agreementRefVO.setId("urn:ngsi-ld:AgreementRef:MyAgreementRef001"); + agreementRefVO.setName("My AgreementRef name"); + + CharacteristicVO characteristicVO = new CharacteristicVO(); + characteristicVO.setName("My customer characteristic name"); + characteristicVO.setValue("My customer characteristic value"); + characteristicVO.setValueType("String"); + + CreditProfileVO creditProfileVO = new CreditProfileVO(); + creditProfileVO.setCreditScore(6); + creditProfileVO.setCreditRiskRating(4); + creditProfileVO.setCreditProfileDate(Instant.now()); + + PaymentMethodRefVO paymentMethodRefVO = new PaymentMethodRefVO(); + paymentMethodRefVO.setId("urn:ngsi-ld:PaymentMethodRef:MyPaymentMethodRef001"); + paymentMethodRefVO.setName("My PaymentMethodRef name"); + customerVO.setContactMedium(List.of(contactMediumVO)); + customerVO.setAccount(List.of(accountRefVO)); + customerVO.setAgreement(List.of(agreementRefVO)); + customerVO.setCharacteristic(List.of(characteristicVO)); + customerVO.setCreditProfile(List.of(creditProfileVO)); + customerVO.setPaymentMethod(List.of(paymentMethodRefVO)); + customerVO.setValidFor( + new TimePeriodVO().startDateTime(Instant.now()) + .endDateTime(Instant.now() + .plus(Duration.of(10, ChronoUnit.DAYS)))); return customerVO; } From b3ccf2365571c598f6466e92a31f2ffa37bca43c Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Wed, 7 Sep 2022 08:00:12 +0200 Subject: [PATCH 07/16] Extend doc --- README.md | 1 + .../test/java/org/fiware/tmforum/customer/CustomerApiIT.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 50080b4b..dc0d6b47 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ There are currently two supporting modules: The api-implementations are inside modules, producing jar-files and oci-containers according to the definitions in the [parent-pom](pom.xml). Current api-implementations: - [party-management-api](party) - implementation of the party-management-api +- [customer-management-api](customer) - implementation of the customer-management-api The project also contains 2 non-module folders: - [api](api) - contains the [OpenApi-Specifications](https://spec.openapis.org/oas/v3.1.0) used by the project. Beside the TMForum-Apis it also contains the specification of the NGSI-LD API. diff --git a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java index 1cb802f8..ff3ba70d 100644 --- a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java +++ b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java @@ -43,7 +43,7 @@ void test() throws JsonProcessingException, ParseException { // Test delete HttpResponse customerDeleteResponse = customerApiController.deleteCustomer(myFancyCustomer.getId()).blockingGet(); assertEquals(HttpStatus.NO_CONTENT, customerDeleteResponse.getStatus(), "A NO_CONTENT response is expected"); - + } private CustomerCreateVO getMyFancyCustomer() throws JsonProcessingException { From 2061c5d61ec5127000df81fafa36f80fa10b0de8 Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Wed, 7 Sep 2022 11:01:50 +0200 Subject: [PATCH 08/16] Adding class for Unit test of customer API controller --- .../rest/CustomerApiControllerTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java diff --git a/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java b/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java new file mode 100644 index 00000000..5a9b1de8 --- /dev/null +++ b/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java @@ -0,0 +1,41 @@ +package org.fiware.tmforum.customer.rest; + +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.reactivex.Single; +import org.fiware.customer.model.*; +import org.fiware.tmforum.common.repository.ReferencesRepository; +import org.fiware.tmforum.common.validation.ReferenceValidationService; +import org.fiware.tmforum.customer.TMForumMapper; +import org.fiware.tmforum.customer.TMForumMapperImpl; +import org.fiware.tmforum.customer.domain.*; +import org.fiware.tmforum.customer.domain.customer.Customer; +import org.fiware.tmforum.customer.repository.CustomerRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + +public class CustomerApiControllerTest { + + private final TMForumMapper tmForumMapper = new TMForumMapperImpl(); + private final CustomerRepository customerRepository = mock(CustomerRepository.class); + private final ReferencesRepository referencesRepository = mock(ReferencesRepository.class); + private final ReferenceValidationService validationService = new ReferenceValidationService(referencesRepository); + private CustomerApiController customerApiController; + + @BeforeEach + public void setup() { + customerApiController = new CustomerApiController(tmForumMapper, customerRepository, validationService); + } + + @DisplayName("Customer created") + @Test + void testCreateCustomer() { + CustomerCreateVO customerCreateVO = new CustomerCreateVO(); + + Single> singleResponse = customerApiController.createCustomer(customerCreateVO); + } +} From 2291a0e9ca7c5f3ea6cc6745e34fd72514789f02 Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Mon, 12 Sep 2022 14:52:29 +0100 Subject: [PATCH 09/16] Add classes for CustomerBill Management API --- api/customer-bill.yaml | 1443 +++++++++++++++++ customer-bill/pom.xml | 257 +++ .../tmforum/customer_bill/Application.java | 31 + .../tmforum/customer_bill/TMForumMapper.java | 124 ++ .../customer_bill/domain/AccountBalance.java | 15 + .../AppliedBillingRateCharacteristic.java | 15 + .../domain/AppliedBillingTaxRate.java | 15 + .../customer_bill/domain/AppliedPayment.java | 16 + .../domain/AttachmentRefOrValue.java | 26 + .../tmforum/customer_bill/domain/BillRef.java | 17 + .../domain/BillingAccountRef.java | 18 + .../domain/FinancialAccountRef.java | 42 + .../tmforum/customer_bill/domain/Money.java | 11 + .../domain/PaymentMethodRef.java | 18 + .../customer_bill/domain/PaymentRef.java | 18 + .../customer_bill/domain/ProductRef.java | 18 + .../customer_bill/domain/Quantity.java | 10 + .../customer_bill/domain/RefEntity.java | 38 + .../customer_bill/domain/RelatedPartyRef.java | 33 + .../customer_bill/domain/StateValue.java | 17 + .../customer_bill/domain/StateValues.java | 15 + .../tmforum/customer_bill/domain/TaxItem.java | 16 + .../customer_bill/domain/TimePeriod.java | 13 + .../AppliedCustomerBillingRate.java | 82 + .../domain/customer_bill/CustomerBill.java | 110 ++ .../customer_bill/CustomerBillOnDemand.java | 60 + .../AppliedCustomerBillingRateRepository.java | 63 + .../CustomerBillOnDemandRepository.java | 67 + .../repository/CustomerBillRepository.java | 62 + ...pliedCustomerBillingRateApiController.java | 42 + .../rest/CustomerBillApiController.java | 50 + .../CustomerBillOnDemandApiController.java | 63 + .../src/main/resources/application.yaml | 44 + customer-bill/src/main/resources/logback.xml | 16 + .../customer/domain/customer/Customer.java | 2 +- pom.xml | 1 + 36 files changed, 2887 insertions(+), 1 deletion(-) create mode 100644 api/customer-bill.yaml create mode 100644 customer-bill/pom.xml create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/Application.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/TMForumMapper.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AccountBalance.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedBillingRateCharacteristic.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedBillingTaxRate.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedPayment.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AttachmentRefOrValue.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/BillRef.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/BillingAccountRef.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/FinancialAccountRef.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/Money.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/PaymentMethodRef.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/PaymentRef.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/ProductRef.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/Quantity.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RefEntity.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RelatedPartyRef.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/StateValue.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/StateValues.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/TaxItem.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/TimePeriod.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/AppliedCustomerBillingRate.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBill.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBillOnDemand.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/AppliedCustomerBillingRateRepository.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/CustomerBillOnDemandRepository.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/CustomerBillRepository.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/AppliedCustomerBillingRateApiController.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiController.java create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiController.java create mode 100644 customer-bill/src/main/resources/application.yaml create mode 100644 customer-bill/src/main/resources/logback.xml diff --git a/api/customer-bill.yaml b/api/customer-bill.yaml new file mode 100644 index 00000000..42cc1f90 --- /dev/null +++ b/api/customer-bill.yaml @@ -0,0 +1,1443 @@ +swagger: '2.0' +info: + title: API CustomerBill + description: |- + ## TMF API Reference: TMF 678 - Customer bill Management + + ### Release: 19.5 - December 2019 + + The Customer Bill Management API allows to find and retrieve one or several customer bills (also called invoices) produced for a customer. A customer bill is an electronic or paper document produced at the end of the billing process. The customer bill gathers and displays different items (applied customer billing rates generated during the rating and billing processes) to be charged to a customer. It represents a total amount due for all the products during the billing period and all significant information like dates, bill reference... + This API provides also operations to find and retrieve the details of applied customer billing rates presented on a customer bill. + Finally, this API allows to request in real-time a customer bill creation and to manage this request. + + ### Resources + - customerBill + - appliedCustomerBillingRate + - customerBillOnDemand + - billingCycle + + ### Operations + Customer Bill Management API performs the following operations : + - Retrieve a customer bill or a collection of customer bills depending on filter criteria. + - Partial update of a customer bill (for administration purposes). + - Retrieve an applied customer billing rate or a collection of applied customer billing rates depending on filter criteria. + - Create a customer bill on demand request, retrieve one or a collection of customer bill on demand request(s) depending on filter criteria. + + - Manage notification of events on customer bill and customer bill on demand. + + Copyright © TM Forum 2018. All Rights Reserved. + version: 4.0.0 +host: serverRoot +basePath: /tmf-api/customerBillManagement/v4/ +schemes: + - https +consumes: + - application/json;charset=utf-8 +produces: + - application/json;charset=utf-8 +tags: + - name: customerBillOnDemand + - name: customerBill + - name: appliedCustomerBillingRate + - name: events subscription +paths: + /customerBillOnDemand: + get: + operationId: listCustomerBillOnDemand + summary: List or find CustomerBillOnDemand objects + description: This operation list or find CustomerBillOnDemand entities + tags: + - customerBillOnDemand + parameters: + - name: fields + description: Comma-separated properties to be provided in response + required: false + in: query + type: string + - name: offset + description: Requested index for start of resources to be provided in response + required: false + in: query + type: integer + - name: limit + description: Requested number of resources to be provided in response + required: false + in: query + type: integer + responses: + '200': + description: Success + headers: + X-Result-Count: + description: Actual number of items returned in the response body + type: integer + X-Total-Count: + description: Total number of items matching criteria + type: integer + schema: + type: array + items: + $ref: '#/definitions/CustomerBillOnDemand' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + post: + operationId: createCustomerBillOnDemand + summary: Creates a CustomerBillOnDemand + description: This operation creates a CustomerBillOnDemand entity. + tags: + - customerBillOnDemand + parameters: + - name: customerBillOnDemand + description: The CustomerBillOnDemand to be created + required: true + schema: + $ref: '#/definitions/CustomerBillOnDemand_Create' + in: body + responses: + '201': + description: Created + schema: + $ref: '#/definitions/CustomerBillOnDemand' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /customerBillOnDemand/{id}: + get: + operationId: retrieveCustomerBillOnDemand + summary: Retrieves a CustomerBillOnDemand by ID + description: This operation retrieves a CustomerBillOnDemand entity. Attribute selection is enabled for all first level attributes. + tags: + - customerBillOnDemand + parameters: + - name: id + description: Identifier of the CustomerBillOnDemand + required: true + type: string + in: path + - name: fields + description: Comma-separated properties to provide in response + required: false + type: string + in: query + responses: + '200': + description: Success + schema: + $ref: '#/definitions/CustomerBillOnDemand' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /customerBill: + get: + operationId: listCustomerBill + summary: List or find CustomerBill objects + description: This operation list or find CustomerBill entities + tags: + - customerBill + parameters: + - name: fields + description: Comma-separated properties to be provided in response + required: false + in: query + type: string + - name: offset + description: Requested index for start of resources to be provided in response + required: false + in: query + type: integer + - name: limit + description: Requested number of resources to be provided in response + required: false + in: query + type: integer + responses: + '200': + description: Success + headers: + X-Result-Count: + description: Actual number of items returned in the response body + type: integer + X-Total-Count: + description: Total number of items matching criteria + type: integer + schema: + type: array + items: + $ref: '#/definitions/CustomerBill' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /customerBill/{id}: + get: + operationId: retrieveCustomerBill + summary: Retrieves a CustomerBill by ID + description: This operation retrieves a CustomerBill entity. Attribute selection is enabled for all first level attributes. + tags: + - customerBill + parameters: + - name: id + description: Identifier of the CustomerBill + required: true + type: string + in: path + - name: fields + description: Comma-separated properties to provide in response + required: false + type: string + in: query + responses: + '200': + description: Success + schema: + $ref: '#/definitions/CustomerBill' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + patch: + operationId: patchCustomerBill + summary: Updates partially a CustomerBill + description: This operation updates partially a CustomerBill entity. + tags: + - customerBill + parameters: + - name: id + description: Identifier of the CustomerBill + required: true + type: string + in: path + - name: customerBill + description: The CustomerBill to be updated + required: true + schema: + $ref: '#/definitions/CustomerBill_Update' + in: body + responses: + '200': + description: Updated + schema: + $ref: '#/definitions/CustomerBill' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /appliedCustomerBillingRate: + get: + operationId: listAppliedCustomerBillingRate + summary: List or find AppliedCustomerBillingRate objects + description: This operation list or find AppliedCustomerBillingRate entities + tags: + - appliedCustomerBillingRate + parameters: + - name: fields + description: Comma-separated properties to be provided in response + required: false + in: query + type: string + - name: offset + description: Requested index for start of resources to be provided in response + required: false + in: query + type: integer + - name: limit + description: Requested number of resources to be provided in response + required: false + in: query + type: integer + responses: + '200': + description: Success + headers: + X-Result-Count: + description: Actual number of items returned in the response body + type: integer + X-Total-Count: + description: Total number of items matching criteria + type: integer + schema: + type: array + items: + $ref: '#/definitions/AppliedCustomerBillingRate' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /appliedCustomerBillingRate/{id}: + get: + operationId: retrieveAppliedCustomerBillingRate + summary: Retrieves a AppliedCustomerBillingRate by ID + description: This operation retrieves a AppliedCustomerBillingRate entity. Attribute selection is enabled for all first level attributes. + tags: + - appliedCustomerBillingRate + parameters: + - name: id + description: Identifier of the AppliedCustomerBillingRate + required: true + type: string + in: path + - name: fields + description: Comma-separated properties to provide in response + required: false + type: string + in: query + responses: + '200': + description: Success + schema: + $ref: '#/definitions/AppliedCustomerBillingRate' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /hub: + post: + operationId: registerListener + summary: Register a listener + description: Sets the communication endpoint address the service instance must use to deliver information about its health state, execution state, failures and metrics. + tags: + - events subscription + parameters: + - name: data + schema: + $ref: '#/definitions/EventSubscriptionInput' + required: true + in: body + description: Data containing the callback endpoint to deliver the information + responses: + '201': + description: Subscribed + schema: + $ref: '#/definitions/EventSubscription' + '400': + description: Bad Request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method Not allowed + schema: + $ref: '#/definitions/Error' + '409': + description: Conflict + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' + /hub/{id}: + delete: + operationId: unregisterListener + summary: Unregister a listener + description: Resets the communication endpoint address the service instance must use to deliver information about its health state, execution state, failures and metrics. + tags: + - events subscription + parameters: + - name: id + type: string + required: true + in: path + description: The id of the registered listener + responses: + '204': + description: Deleted + '400': + description: Bad request + schema: + $ref: '#/definitions/Error' + '401': + description: Unauthorized + schema: + $ref: '#/definitions/Error' + '403': + description: Forbidden + schema: + $ref: '#/definitions/Error' + '404': + description: Not Found + schema: + $ref: '#/definitions/Error' + '405': + description: Method not allowed + schema: + $ref: '#/definitions/Error' + '500': + description: Internal Server Error + schema: + $ref: '#/definitions/Error' +definitions: + AccountBalance: + type: object + description: Balances linked to the account + required: + - amount + - balanceType + - validFor + properties: + balanceType: + type: string + description: 'Type of the balance : deposit balance, disputed balance, loyalty balance, receivable balance...' + amount: + $ref: '#/definitions/Money' + description: Balance amount + validFor: + $ref: '#/definitions/TimePeriod' + description: Balance validity period + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + Any: {} + AppliedBillingRateCharacteristic: + type: object + description: An applied billing rate has dynamic characteristics according to the its type (characteristics are based on the service type, line of business or on others parameters) + required: + - name + - value + properties: + name: + type: string + description: Name of the characteristic + valueType: + type: string + description: Data type of the value of the characteristic + value: + $ref: '#/definitions/Any' + description: The value of the characteristic + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + AppliedBillingTaxRate: + type: object + description: The applied billing tax rate represents taxes applied billing rate it refers to. It is calculated during the billing process. + properties: + taxCategory: + type: string + description: A categorization of the tax rate + taxRate: + type: number + format: float + description: Applied rate + taxAmount: + $ref: '#/definitions/Money' + description: Tax amount expressed in the given currency + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + AppliedCustomerBillingRate: + type: object + description: A customer bill displays applied billing rates created before or during the billing process. + required: + - id + properties: + id: + type: string + description: Unique identifier of the customer applied billing rate + href: + type: string + description: Reference of the customer applied billing rate + date: + type: string + format: date-time + description: Creation date of the applied billing rate + description: + type: string + description: Additional data to be displayed on the bill for this customer applied billing rate + isBilled: + type: boolean + description: If isBilled = true then bill should be provided, if false then billingAccount should be provided + name: + type: string + description: Name of the customer applied billing rate + type: + type: string + description: 'Type of the applied billing rate : appliedBillingCharge (any kind of charge except taxation charges : recurringCharge, oneTimeCharge, usageCharge), appliedBillingCredit (any kind of credit : rebate or productAlteration) or appliedPenaltyCharge (penalty charges such as late fees, payment rejection fees,...)' + appliedTax: + type: array + items: + $ref: '#/definitions/AppliedBillingTaxRate' + bill: + $ref: '#/definitions/BillRef' + billingAccount: + $ref: '#/definitions/BillingAccountRef' + characteristic: + type: array + items: + $ref: '#/definitions/AppliedBillingRateCharacteristic' + periodCoverage: + $ref: '#/definitions/TimePeriod' + description: periodCoverage for RecurringCharge (RC) indicating the RC coverage period dates for different purposes, such as RC proration, display on bill, GL reporting, etc. periodCoverage for OC start and end date will be the same + product: + $ref: '#/definitions/ProductRef' + description: Usually this information should be provided by the PRODUCT, which implies that there is a valid reference to product. In this case, this property should be empty. For all other situations, a text or structured info could be provided using this property. Regular modelling would suggest tu use the reforvalue pattern for this case. It is not choosen here because it would generate declarational dependencies which would be hard to maintain. + taxExcludedAmount: + $ref: '#/definitions/Money' + taxIncludedAmount: + $ref: '#/definitions/Money' + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + AppliedPayment: + type: object + description: The applied payment is the result of lettering process. It enables to assign automatically or manually part of incoming payment amount to a bill. + properties: + appliedAmount: + $ref: '#/definitions/Money' + payment: + $ref: '#/definitions/PaymentRef' + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + Attachment: + type: object + description: Complements the description of an element (for instance a product) through video, pictures... + properties: + id: + type: string + description: Unique identifier for this particular attachment + href: + type: string + description: URI for this Attachment + attachmentType: + type: string + description: Attachment type such as video, picture + content: + type: string + description: The actual contents of the attachment object, if embedded, encoded as base64 + description: + type: string + description: A narrative text describing the content of the attachment + mimeType: + type: string + description: Attachment mime type such as extension file for video, picture and document + name: + type: string + description: The name of the attachment + url: + type: string + description: Uniform Resource Locator, is a web page address (a subset of URI) + size: + $ref: '#/definitions/Quantity' + description: The size of the attachment. + validFor: + $ref: '#/definitions/TimePeriod' + description: The period of time for which the attachment is valid + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + AttachmentRef: + type: object + description: Attachment reference. An attachment complements the description of an element (for instance a product) through video, pictures + properties: + id: + type: string + description: Unique-Identifier for this attachment + href: + type: string + description: URL serving as reference for the attachment resource + description: + type: string + description: A narrative text describing the content of the attachment + name: + type: string + description: Name of the related entity. + url: + type: string + description: Link to the attachment media/content + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + AttachmentRefOrValue: + type: object + description: An attachment by value or by reference. For AttachmentRefOrValue, the attribute type,schemaLocation and referredType are related to the contained entity and not to AttchmentRefOrValue itself + properties: + id: + type: string + description: Unique identifier for this particular attachment + href: + type: string + description: URI for this Attachment + attachmentType: + type: string + description: Attachment type such as video, picture + content: + type: string + description: The actual contents of the attachment object, if embedded, encoded as base64 + description: + type: string + description: A narrative text describing the content of the attachment + mimeType: + type: string + description: Attachment mime type such as extension file for video, picture and document + name: + type: string + description: The name of the attachment + url: + type: string + description: Uniform Resource Locator, is a web page address (a subset of URI) + size: + $ref: '#/definitions/Quantity' + description: The size of the attachment. + validFor: + $ref: '#/definitions/TimePeriod' + description: The period of time for which the attachment is valid + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + BillRef: + type: object + description: Bill reference. + properties: + id: + type: string + description: Unique-Identifier for this <123> + href: + type: string + description: URL serving as reference for the resource + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + BillingAccountRef: + type: object + description: Reference to the billing account in case of not billed item. + properties: + id: + type: string + description: Unique-Identifier for this <123> + href: + type: string + description: URL serving as reference for the resource + name: + type: string + description: Name of the Billingaccount + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + Characteristic: + type: object + description: Describes a given characteristic of an object or entity through a name/value pair. + required: + - name + - value + properties: + name: + type: string + description: Name of the characteristic + valueType: + type: string + description: Data type of the value of the characteristic + value: + $ref: '#/definitions/Any' + description: The value of the characteristic + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + CustomerBill: + type: object + description: |- + The billing account receives all charges (recurring, one time and usage) of the offers and products assigned to it during order process. Periodically according to billing cycle specifications attached to the billing account or as a result of an event, a customer bill (aka invoice) is produced. This customer bill concerns different related parties which play a role on it : for example, a customer bill is produced by an operator, is sent to a bill receiver and has to be paid by a payer. + A payment method could be assigned to the customer bill to build the call of payment. Lettering process enables to assign automatically or manually incoming amount from payments to customer bills (payment items). + A tax item is created for each tax rate used in the customer bill. + The financial account represents a financial entity which records all customer’s accounting events : payment amount are recorded as credit and invoices amount are recorded as debit. It gives the customer overall balance (account balance). + The customer bill is linked to one or more documents that can be downloaded via a provided url. + properties: + id: + type: string + description: Unique identifier of he bill + href: + type: string + description: Bill unique reference + billDate: + type: string + format: date-time + description: Bill date + billNo: + type: string + description: Bill reference known by the customer or the party and displayed on the bill. Could be different from the id + category: + type: string + description: 'Category of the bill produced : normal, duplicate, interim, last, trial customer or credit note for example' + lastUpdate: + type: string + format: date-time + description: Date of bill last update + nextBillDate: + type: string + format: date-time + description: ). Approximate date of the next bill production given for information (only used for onCycle bill) + paymentDueDate: + type: string + format: date-time + description: Date at which the amount due should have been paid + runType: + type: string + description: onCycle (a bill can be created as a result of a cycle run) or offCycle (a bill can be created as a result of other events such as customer request or account close) + amountDue: + $ref: '#/definitions/Money' + appliedPayment: + type: array + items: + $ref: '#/definitions/AppliedPayment' + billDocument: + type: array + items: + $ref: '#/definitions/AttachmentRefOrValue' + billingAccount: + $ref: '#/definitions/BillingAccountRef' + billingPeriod: + $ref: '#/definitions/TimePeriod' + financialAccount: + $ref: '#/definitions/FinancialAccountRef' + paymentMethod: + $ref: '#/definitions/PaymentMethodRef' + relatedParty: + type: array + items: + $ref: '#/definitions/RelatedPartyRef' + remainingAmount: + $ref: '#/definitions/Money' + state: + $ref: '#/definitions/stateValue' + taxExcludedAmount: + $ref: '#/definitions/Money' + taxIncludedAmount: + $ref: '#/definitions/Money' + taxItem: + type: array + items: + $ref: '#/definitions/TaxItem' + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + CustomerBill_Update: + type: object + description: |- + The billing account receives all charges (recurring, one time and usage) of the offers and products assigned to it during order process. Periodically according to billing cycle specifications attached to the billing account or as a result of an event, a customer bill (aka invoice) is produced. This customer bill concerns different related parties which play a role on it : for example, a customer bill is produced by an operator, is sent to a bill receiver and has to be paid by a payer. + A payment method could be assigned to the customer bill to build the call of payment. Lettering process enables to assign automatically or manually incoming amount from payments to customer bills (payment items). + A tax item is created for each tax rate used in the customer bill. + The financial account represents a financial entity which records all customer’s accounting events : payment amount are recorded as credit and invoices amount are recorded as debit. It gives the customer overall balance (account balance). + The customer bill is linked to one or more documents that can be downloaded via a provided url. + Skipped properties: id,href,amountDue,appliedPayment,billDate,billDocument,billNo,billingAccount,billingPeriod,category,financialAccount,lastUpdate,nextBillDate,paymentDueDate,paymentMethod,relatedParty,remainingAmount,runType,taxExcludedAmount,taxIncludedAmount,taxItem + properties: + state: + $ref: '#/definitions/stateValue' + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + CustomerBillOnDemand: + type: object + description: This resource is used to manage the creation request of a customer bill in real-time (on demand). + properties: + id: + type: string + description: Unique identifier of the customer bill on demand request given by the server + href: + type: string + description: Reference of the customer bill on demand request + description: + type: string + description: Additional data describing the customer bill on demand request + lastUpdate: + type: string + description: The last date time when the customer bill on demand has been updated + name: + type: string + description: Friendly name to identify the customer bill on demand request + billingAccount: + $ref: '#/definitions/BillingAccountRef' + customerBill: + $ref: '#/definitions/BillRef' + relatedParty: + $ref: '#/definitions/RelatedPartyRef' + state: + $ref: '#/definitions/StateValues' + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + CustomerBillOnDemand_Create: + type: object + description: |- + This resource is used to manage the creation request of a customer bill in real-time (on demand). + Skipped properties: id,href + properties: + description: + type: string + description: Additional data describing the customer bill on demand request + lastUpdate: + type: string + description: The last date time when the customer bill on demand has been updated + name: + type: string + description: Friendly name to identify the customer bill on demand request + billingAccount: + $ref: '#/definitions/BillingAccountRef' + customerBill: + $ref: '#/definitions/BillRef' + relatedParty: + $ref: '#/definitions/RelatedPartyRef' + state: + $ref: '#/definitions/StateValues' + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + EntityRef: + type: object + description: Entity reference schema to be use for all entityRef class. + properties: + id: + type: string + description: Unique identifier of a related entity. + href: + type: string + description: Reference of the related entity. + name: + type: string + description: Name of the related entity. + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + FinancialAccountRef: + type: object + description: AccountReceivable reference. An account of money owed by a party to another entity in exchange for goods or services that have been delivered or used. An account receivable aggregates the amounts of one or more party accounts (billing or settlement) owned by a given party. + properties: + id: + type: string + description: Unique identifier of the account + href: + type: string + description: Unique reference of the account + name: + type: string + description: Name of the account + accountBalance: + type: array + items: + $ref: '#/definitions/AccountBalance' + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + Money: + type: object + description: A base / value business entity used to represent money + properties: + unit: + type: string + description: Currency (ISO4217 norm uses 3 letters to define the currency) + value: + type: number + format: float + description: A positive floating point number + PaymentMethodRef: + type: object + description: PaymentMethod reference. A payment method defines a specific mean of payment (e.g direct debit). + properties: + id: + type: string + description: Unique identifier of the payment mean + href: + type: string + description: Reference of the payment mean + name: + type: string + description: Name of the payment mean + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + PaymentRef: + type: object + description: If an immediate payment has been done at the product order submission, the payment information are captured and stored (as a reference) in the order. + properties: + id: + type: string + description: Unique identifier of a related entity. + href: + type: string + description: Reference of the related entity. + name: + type: string + description: A name for the payment + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + ProductRef: + type: object + properties: + id: + type: string + description: Unique identifier of a related entity. + href: + type: string + description: Reference of the related entity. + name: + type: string + description: Name of the related entity. + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + Quantity: + type: object + description: An amount in a given unit + properties: + amount: + default: 1 + type: number + format: float + description: Numeric value in a given unit + units: + type: string + description: Unit + Reference: + type: object + description: General Referencing Resource Schema + properties: + id: + type: string + description: Unique-Identifier for this <123> + href: + type: string + description: URL serving as reference for the resource + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + RelatedPartyRef: + type: object + description: RelatedParty reference. A related party defines party or party role linked to a specific entity. + properties: + id: + type: string + description: Unique identifier of a related party + href: + type: string + description: Reference of the related party, could be a party reference or a party role reference + name: + type: string + description: Name of the related party + role: + type: string + description: Role of the related party. + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + '@referredType': + type: string + description: The actual type of the target instance when needed for disambiguation. + required: + - id + StateValues: + type: string + description: '' + enum: + - inProgress + - rejected + - done + - terminatedWithError + TaxItem: + type: object + description: A tax item is created for each tax rate and tax type used in the bill. + properties: + taxCategory: + type: string + description: Tax category + taxRate: + type: number + format: float + description: Applied rate of the tax + taxAmount: + $ref: '#/definitions/Money' + description: Amount of tax expressed in the given currency + '@baseType': + type: string + description: When sub-classing, this defines the super-class + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name + TimePeriod: + type: object + description: A period of time, either as a deadline (endDateTime only) a startDateTime only, or both + properties: + endDateTime: + type: string + format: date-time + description: End of the time period, using IETC-RFC-3339 format + startDateTime: + type: string + format: date-time + description: Start of the time period, using IETC-RFC-3339 format. If you define a start, you must also define an end + stateValue: + type: string + description: '' + enum: + - new + - onHold + - validated + - sent + - partiallyPaid + - settled + EventSubscription: + type: object + description: Sets the communication endpoint address the service instance must use to deliver notification information + required: + - id + - callback + properties: + id: + type: string + description: Id of the listener + callback: + type: string + description: The callback being registered. + query: + type: string + description: additional data to be passed + EventSubscriptionInput: + type: object + description: Sets the communication endpoint address the service instance must use to deliver notification information + required: + - callback + properties: + callback: + type: string + description: The callback being registered. + query: + type: string + description: additional data to be passed + Error: + description: Used when an API throws an Error, typically with a HTTP error response-code (3xx, 4xx, 5xx) + type: object + required: + - code + - reason + properties: + code: + type: string + description: Application relevant detail, defined in the API or a common list. + reason: + type: string + description: Explanation of the reason for the error which can be shown to a client user. + message: + type: string + description: More details and corrective actions related to the error which can be shown to a client user. + status: + type: string + description: HTTP Error code extension + referenceError: + type: string + format: uri + description: URI of documentation describing the error. + '@baseType': + type: string + description: When sub-classing, this defines the super-class. + '@schemaLocation': + type: string + format: uri + description: A URI to a JSON-Schema file that defines additional attributes and relationships + '@type': + type: string + description: When sub-classing, this defines the sub-class entity name. diff --git a/customer-bill/pom.xml b/customer-bill/pom.xml new file mode 100644 index 00000000..a4606c71 --- /dev/null +++ b/customer-bill/pom.xml @@ -0,0 +1,257 @@ + + + 4.0.0 + org.fiware.tmforum + customer-bill + 0.1 + + + org.fiware + tmforum + 0.1 + + + + + org.fiware.tmforum + common + ${project.version} + compile + + + org.fiware.tmforum + mapping + ${project.version} + compile + + + + + org.projectlombok + lombok + + + org.mapstruct + mapstruct + + + + + io.micronaut + micronaut-inject + compile + + + io.micronaut + micronaut-validation + compile + + + io.micronaut + micronaut-runtime + compile + + + io.micronaut + micronaut-management + compile + + + io.micronaut.cache + micronaut-cache-caffeine + compile + + + io.micronaut + micronaut-http-client + compile + + + io.micronaut + micronaut-http-server-netty + compile + + + io.micronaut + micronaut-jackson-databind + compile + + + io.micronaut.rxjava2 + micronaut-rxjava2 + compile + + + io.micronaut + micronaut-jackson-core + compile + + + io.kokuwa.micronaut + micronaut-logging + ${version.io.kokuwa.micronaut.logging} + compile + + + + + javax.inject + javax.inject + + + javax.annotation + javax.annotation-api + + + + com.google.code.findbugs + annotations + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + compile + + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.jupiter + junit-jupiter-params + test + + + io.micronaut.test + micronaut-test-junit5 + test + + + io.micronaut.test + micronaut-test-core + test + + + + org.mockito + mockito-all + test + + + org.mockito + mockito-junit-jupiter + test + + + org.awaitility + awaitility + test + + + + + + + src/main/resources + true + + + src/test/resources + true + + + + + + org.openapitools + openapi-generator-maven-plugin + ${version.org.openapitools.generator-maven-plugin} + + + openapi-customer-bill-api + generate-sources + + generate + + + ${project.parent.basedir}/api/customer-bill.yaml + org.fiware.customer_bill.api + true + org.fiware.customer_bill.model + true + micronaut + false + false + VO + ${project.build.directory} + + true + false + true + true + true + false + true + false + true + + + java.util.Date=java.time.Instant + + + + + + + io.kokuwa.micronaut + micronaut-openapi-codegen + ${version.io.kokuwa.micronaut.codegen} + + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + org.apache.maven.plugins + maven-jar-plugin + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + io.kokuwa.maven + k3s-maven-plugin + + + + + com.google.cloud.tools + jib-maven-plugin + + + + \ No newline at end of file diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/Application.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/Application.java new file mode 100644 index 00000000..c551de93 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/Application.java @@ -0,0 +1,31 @@ +package org.fiware.tmforum.customer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.micronaut.context.annotation.Bean; +import io.micronaut.context.annotation.Factory; +import io.micronaut.runtime.Micronaut; +import org.fiware.tmforum.mapping.EntitiesRepository; +import org.fiware.tmforum.mapping.EntityVOMapper; +import org.fiware.tmforum.mapping.JavaObjectMapper; + +/** + * Base application as starting point + */ +@Factory +public class Application { + + public static void main(String[] args) { + Micronaut.run(Application.class, args); + } + + @Bean + public EntityVOMapper entityVOMapper(ObjectMapper objectMapper, EntitiesRepository entitiesRepository) { + return new EntityVOMapper(objectMapper, entitiesRepository); + } + + @Bean + public JavaObjectMapper javaObjectMapper(ObjectMapper objectMapper) { + return new JavaObjectMapper(); + } + +} \ No newline at end of file diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/TMForumMapper.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/TMForumMapper.java new file mode 100644 index 00000000..46d9c8e7 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/TMForumMapper.java @@ -0,0 +1,124 @@ +package org.fiware.tmforum.customer_bill; + +import org.fiware.customer_bill.model.*; +import org.fiware.tmforum.customer_bill.domain.*; +import org.fiware.tmforum.customer_bill.domain.customer_bill.AppliedCustomerBillingRate; +import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBill; +import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBillOnDemand; +import org.fiware.tmforum.mapping.MappingException; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; + +/** + * Mapper between the internal model and api-domain objects + */ +@Mapper(componentModel = "jsr330") +public interface TMForumMapper { + + String ID_TEMPLATE = "urn:ngsi-ld:%s:%s"; + + CustomerBillVO map(CustomerBill customerBill); + CustomerBill map(CustomerBillVO customerBillVO); + + @Mapping(target = "id", expression = "java(java.lang.String.format(ID_TEMPLATE, \"customer_bill_on_demand\", java.util.UUID.randomUUID()))") + @Mapping(target = "href", ignore = true) + CustomerBillOnDemandVO map(CustomerBillOnDemandCreateVO customerBillOnDemandCreateVO); + CustomerBillOnDemandVO map(CustomerBillOnDemand customerBillOnDemand); + CustomerBillOnDemand map(CustomerBillOnDemandVO customerBillOnDemandVO); + + AppliedCustomerBillingRate map(AppliedCustomerBillingRateVO appliedCustomerBillingRateVO); + + @Mapping(target = "isBilled", source = "billed") + AppliedCustomerBillingRateVO map(AppliedCustomerBillingRate appliedCustomerBillingRate); + + TimePeriodVO map(TimePeriod timePeriod); + TimePeriod map(TimePeriodVO value); + + Money map(MoneyVO moneyVO); + MoneyVO map(Money money); + + AppliedPayment map(AppliedPaymentVO appliedPaymentVO); + AppliedPaymentVO map(AppliedPayment appliedPayment); + + PaymentRef map(PaymentRefVO paymentRefVO); + PaymentRefVO map(PaymentRef paymentRef); + + AttachmentRefOrValue map(AttachmentRefOrValueVO attachmentRefOrValueVO); + AttachmentRefOrValueVO map(AttachmentRefOrValue attachmentRefOrValue); + + Quantity map(QuantityVO quantityVO); + QuantityVO map(Quantity quantity); + + BillingAccountRef map(BillingAccountRefVO billingAccountRefVO); + BillingAccountRefVO map(BillingAccountRef billingAccountRef); + + FinancialAccountRef map(FinancialAccountRefVO financialAccountRefVO); + FinancialAccountRefVO map(FinancialAccountRef financialAccountRef); + + AccountBalance map(AccountBalanceVO accountBalanceVO); + AccountBalanceVO map(AccountBalance accountBalance); + + PaymentMethodRef map(PaymentMethodRefVO paymentMethodRefVO); + PaymentMethodRefVO map(PaymentMethodRef paymentMethodRef); + + RelatedPartyRef map(RelatedPartyRefVO relatedPartyRefVO); + RelatedPartyRefVO map(RelatedPartyRef relatedPartyRef); + + StateValue map(StateValueVO stateValueVO); + StateValueVO map(StateValue stateValue); + + StateValues map(StateValuesVO stateValuesVO); + StateValuesVO map(StateValues stateValues); + + TaxItem map(TaxItemVO taxItemVO); + TaxItemVO map(TaxItem taxItem); + + BillRef map(BillRefVO billRefVO); + BillRefVO map(BillRef billRef); + + AppliedBillingTaxRate map(AppliedBillingTaxRateVO appliedBillingTaxRateVO); + AppliedBillingTaxRateVO map(AppliedBillingTaxRate appliedBillingTaxRate); + + AppliedBillingRateCharacteristic map(AppliedBillingRateCharacteristicVO appliedBillingRateCharacteristicVO); + AppliedBillingRateCharacteristicVO map(AppliedBillingRateCharacteristic appliedBillingRateCharacteristic); + + ProductRef map(ProductRefVO productRefVO); + ProductRefVO map(ProductRef productRef); + + default URL map(String value) { + if (value == null) { + return null; + } + try { + return new URL(value); + } catch (MalformedURLException e) { + throw new MappingException(String.format("%s is not a URL.", value), e); + } + } + + default String map(URL value) { + if (value == null) { + return null; + } + return value.toString(); + } + + default URI mapToURI(String value) { + if (value == null) { + return null; + } + return URI.create(value); + } + + default String mapFromURI(URI value) { + if (value == null) { + return null; + } + return value.toString(); + } + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AccountBalance.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AccountBalance.java new file mode 100644 index 00000000..abb49c1a --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AccountBalance.java @@ -0,0 +1,15 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +@Data +@EqualsAndHashCode(callSuper = true) +public class AccountBalance extends Entity { + + private String balanceType; + private Money amount; + private TimePeriod validFor; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedBillingRateCharacteristic.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedBillingRateCharacteristic.java new file mode 100644 index 00000000..ca7fad56 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedBillingRateCharacteristic.java @@ -0,0 +1,15 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +@Data +@EqualsAndHashCode(callSuper = true) +public class AppliedBillingRateCharacteristic extends Entity { + + private String name; + private String valueType; + private Object value; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedBillingTaxRate.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedBillingTaxRate.java new file mode 100644 index 00000000..33a96775 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedBillingTaxRate.java @@ -0,0 +1,15 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +@Data +@EqualsAndHashCode(callSuper = true) +public class AppliedBillingTaxRate extends Entity { + + private String taxCategory; + private Float taxRate; + private Money taxAmount; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedPayment.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedPayment.java new file mode 100644 index 00000000..ed7fe0d2 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AppliedPayment.java @@ -0,0 +1,16 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.customer_bill.model.MoneyVO; +import org.fiware.customer_bill.model.PaymentRefVO; +import org.fiware.tmforum.common.domain.Entity; + +@Data +@EqualsAndHashCode(callSuper = true) +public class AppliedPayment extends Entity { + + private Money appliedAmount; + private PaymentRef payment; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AttachmentRefOrValue.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AttachmentRefOrValue.java new file mode 100644 index 00000000..5d2c8ead --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/AttachmentRefOrValue.java @@ -0,0 +1,26 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +import java.net.URL; + +@EqualsAndHashCode(callSuper = true) +@Data +public class AttachmentRefOrValue extends Entity { + + private String id; + private URL href; + private String attachmentType; + private String content; + private String description; + private String mimeType; + private URL url; + private Quantity size; + private TimePeriod validFor; + private String name; + private String atReferredType; + + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/BillRef.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/BillRef.java new file mode 100644 index 00000000..9ff4372f --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/BillRef.java @@ -0,0 +1,17 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +import java.net.URL; + +@EqualsAndHashCode(callSuper = true) +@Data +public class BillRef extends Entity { + + private String id; + private URL href; + private String atReferredType; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/BillingAccountRef.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/BillingAccountRef.java new file mode 100644 index 00000000..28326bd6 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/BillingAccountRef.java @@ -0,0 +1,18 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +import java.net.URL; + +@EqualsAndHashCode(callSuper = true) +@Data +public class BillingAccountRef extends Entity { + + private String id; + private URL href; + private String name; + private String atReferredType; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/FinancialAccountRef.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/FinancialAccountRef.java new file mode 100644 index 00000000..fb92dba6 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/FinancialAccountRef.java @@ -0,0 +1,42 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.fiware.tmforum.common.domain.Entity; +import org.fiware.tmforum.common.domain.EntityWithId; +import org.fiware.tmforum.mapping.annotations.AttributeGetter; +import org.fiware.tmforum.mapping.annotations.AttributeSetter; +import org.fiware.tmforum.mapping.annotations.AttributeType; +import org.fiware.tmforum.mapping.annotations.MappingEnabled; + +import java.net.URL; +import java.util.List; + +@MappingEnabled(entityType = FinancialAccountRef.TYPE_FINANCIAL_ACCOUNT_REF) +@EqualsAndHashCode(callSuper = true) +public class FinancialAccountRef extends EntityWithId { + + public static final String TYPE_FINANCIAL_ACCOUNT_REF = "financial-account-ref"; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "href")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "href")})) + private URL href; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "name")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name")})) + private String name; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "accountBalance")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "accountBalance", targetClass = AccountBalance.class)})) + private List accountBalance; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "atReferredType")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "atReferredType")})) + private String atReferredType; + + public FinancialAccountRef(String id) { + super(FinancialAccountRef.TYPE_FINANCIAL_ACCOUNT_REF, id); + } +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/Money.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/Money.java new file mode 100644 index 00000000..0b676641 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/Money.java @@ -0,0 +1,11 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; + +@Data +public class Money { + + private Float value; + private String unit; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/PaymentMethodRef.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/PaymentMethodRef.java new file mode 100644 index 00000000..9737c7dc --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/PaymentMethodRef.java @@ -0,0 +1,18 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +import java.net.URL; + +@EqualsAndHashCode(callSuper = true) +@Data +public class PaymentMethodRef extends Entity { + + private String id; + private URL href; + private String name; + private String atReferredType; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/PaymentRef.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/PaymentRef.java new file mode 100644 index 00000000..c10a5c9a --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/PaymentRef.java @@ -0,0 +1,18 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +import java.net.URL; + +@EqualsAndHashCode(callSuper = true) +@Data +public class PaymentRef extends Entity { + + private String id; + private URL href; + private String name; + private String atReferredType; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/ProductRef.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/ProductRef.java new file mode 100644 index 00000000..eb6d7da2 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/ProductRef.java @@ -0,0 +1,18 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.tmforum.common.domain.Entity; + +import java.net.URL; + +@EqualsAndHashCode(callSuper = true) +@Data +public class ProductRef extends Entity { + + private String id; + private URL href; + private String name; + private String atReferredType; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/Quantity.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/Quantity.java new file mode 100644 index 00000000..89ae9b1f --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/Quantity.java @@ -0,0 +1,10 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; + +@Data +public class Quantity { + + private Float amount; + private String units; +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RefEntity.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RefEntity.java new file mode 100644 index 00000000..3da3e0c9 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RefEntity.java @@ -0,0 +1,38 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.fiware.tmforum.common.domain.Entity; +import org.fiware.tmforum.common.validation.ReferencedEntity; +import org.fiware.tmforum.mapping.annotations.*; + +import java.net.URI; + +@EqualsAndHashCode +public abstract class RefEntity extends Entity implements ReferencedEntity { + + @Getter(onMethod = @__({@RelationshipObject, @DatasetId})) + final URI id; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "href")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "href")})) + private URI href; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "name")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name")})) + private String name; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "@referredType")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "@referredType")})) + private String atReferredType; + + protected RefEntity(String id) { + this.id = URI.create(id); + } + + protected RefEntity(URI id) { + this.id = id; + } + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RelatedPartyRef.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RelatedPartyRef.java new file mode 100644 index 00000000..9c5f6337 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RelatedPartyRef.java @@ -0,0 +1,33 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBill; +import org.fiware.tmforum.mapping.annotations.*; + +import java.util.List; + +@MappingEnabled(entityType = {CustomerBill.TYPE_CUSTOMER_BILL}) +@EqualsAndHashCode(callSuper = true) +public class RelatedPartyRef extends RefEntity { + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "name", embedProperty = true)})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name", targetClass = String.class)})) + private String name; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "role", embedProperty = true)})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "role", targetClass = String.class)})) + private String role; + + public RelatedPartyRef(String id) { + super(id); + } + + @Override + @Ignore + public List getReferencedTypes() { + return List.of(CustomerBill.TYPE_CUSTOMER_BILL); + } + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/StateValue.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/StateValue.java new file mode 100644 index 00000000..c398c54a --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/StateValue.java @@ -0,0 +1,17 @@ +package org.fiware.tmforum.customer_bill.domain; + +public enum StateValue { + + NEW("new"), + ONHOLD("onHold"), + VALIDATED("validated"), + SENT("sent"), + PARTIALLYPAID("partiallyPaid"), + SETTLED("settled"); + + private final String value; + + StateValue(String value) { + this.value = value; + } +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/StateValues.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/StateValues.java new file mode 100644 index 00000000..b96aa913 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/StateValues.java @@ -0,0 +1,15 @@ +package org.fiware.tmforum.customer_bill.domain; + +public enum StateValues { + + INPROGRESS("inProgress"), + REJECTED("rejected"), + DONE("done"), + TERMINATEDWITHERROR("terminatedWithError"); + + private final String value; + + StateValues(String value) { + this.value = value; + } +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/TaxItem.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/TaxItem.java new file mode 100644 index 00000000..6a6e3b3c --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/TaxItem.java @@ -0,0 +1,16 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.fiware.customer_bill.model.MoneyVO; +import org.fiware.tmforum.common.domain.Entity; + +@Data +@EqualsAndHashCode(callSuper = true) +public class TaxItem extends Entity { + + private String taxCategory; + private Float taxRate; + private Money taxAmount; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/TimePeriod.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/TimePeriod.java new file mode 100644 index 00000000..b27f81ad --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/TimePeriod.java @@ -0,0 +1,13 @@ +package org.fiware.tmforum.customer_bill.domain; + +import lombok.Data; + +import java.time.Instant; + +@Data +public class TimePeriod { + + private Instant endDateTime; + private Instant startDateTime; + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/AppliedCustomerBillingRate.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/AppliedCustomerBillingRate.java new file mode 100644 index 00000000..f19ca97c --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/AppliedCustomerBillingRate.java @@ -0,0 +1,82 @@ +package org.fiware.tmforum.customer_bill.domain.customer_bill; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.fiware.tmforum.common.domain.EntityWithId; +import org.fiware.tmforum.customer_bill.domain.*; +import org.fiware.tmforum.mapping.annotations.AttributeGetter; +import org.fiware.tmforum.mapping.annotations.AttributeSetter; +import org.fiware.tmforum.mapping.annotations.AttributeType; +import org.fiware.tmforum.mapping.annotations.MappingEnabled; + +import java.net.URL; +import java.time.Instant; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@MappingEnabled(entityType = AppliedCustomerBillingRate.TYPE_APPLIED_CUSTOMER_BILLING_RATE) +public class AppliedCustomerBillingRate extends EntityWithId { + + public static final String TYPE_APPLIED_CUSTOMER_BILLING_RATE = "applied_customer_billing_rate"; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "href")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "href")})) + private URL href; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "date")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "date")})) + private Instant date; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "description")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "description")})) + private String description; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "isBilled")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "isBilled")})) + private boolean isBilled; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "name")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name")})) + private String name; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "type")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "type")})) + private String type; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "billingAccount")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "billingAccount", targetClass = AppliedBillingTaxRate.class)})) + private List appliedTax; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "bill")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "bill")})) + private BillRef bill; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "billingAccount")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "billingAccount")})) + private BillingAccountRef billingAccount; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "characteristic")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "characteristic", targetClass = AppliedBillingRateCharacteristic.class)})) + private List characteristic; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "periodCoverage")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "periodCoverage", targetClass = TimePeriod.class)})) + private TimePeriod periodCoverage; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "product")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "product", targetClass = ProductRef.class)})) + private ProductRef product; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "taxExcludedAmount")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "taxExcludedAmount")})) + private Money taxExcludedAmount; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "taxIncludedAmount")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "taxIncludedAmount")})) + private Money taxIncludedAmount; + + public AppliedCustomerBillingRate(String id) { + super(AppliedCustomerBillingRate.TYPE_APPLIED_CUSTOMER_BILLING_RATE, id); + } +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBill.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBill.java new file mode 100644 index 00000000..996199bc --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBill.java @@ -0,0 +1,110 @@ +package org.fiware.tmforum.customer_bill.domain.customer_bill; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.fiware.tmforum.common.domain.EntityWithId; +import org.fiware.tmforum.customer_bill.domain.*; +import org.fiware.tmforum.mapping.annotations.AttributeGetter; +import org.fiware.tmforum.mapping.annotations.AttributeSetter; +import org.fiware.tmforum.mapping.annotations.AttributeType; +import org.fiware.tmforum.mapping.annotations.MappingEnabled; + +import java.net.URL; +import java.time.Instant; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@MappingEnabled(entityType = CustomerBill.TYPE_CUSTOMER_BILL) +public class CustomerBill extends EntityWithId { + + public static final String TYPE_CUSTOMER_BILL = "customer_bill"; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "href")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "href")})) + private URL href; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "billDate")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "billDate")})) + private Instant billDate; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "billNo")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "billNo")})) + private String billNo; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "category")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "category")})) + private String category; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "lastUpdate")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "lastUpdate")})) + private Instant lastUpdate; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "nextBillDate")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "nextBillDate")})) + private Instant nextBillDate; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "paymentDueDate")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "paymentDueDate")})) + private Instant paymentDueDate; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "runType")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "runType")})) + private String runType; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "amountDue")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "amountDue")})) + private Money amountDue; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "appliedPayment")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "appliedPayment", targetClass = AppliedPayment.class)})) + private List appliedPayment; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "billDocument")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "billDocument", targetClass = AttachmentRefOrValue.class)})) + private List billDocument; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "billingAccount")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "billingAccount", targetClass = BillingAccountRef.class)})) + private BillingAccountRef billingAccount; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "billingPeriod")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "billingPeriod", targetClass = TimePeriod.class)})) + private TimePeriod billingPeriod; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "financialAccount")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "financialAccount", targetClass = FinancialAccountRef.class)})) + private FinancialAccountRef financialAccount; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "paymentMethod")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "paymentMethod", targetClass = PaymentMethodRef.class)})) + private PaymentMethodRef paymentMethod; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "relatedParty")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "relatedParty", targetClass = RelatedPartyRef.class, fromProperties = true)})) + private List relatedParty; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "remainingAmount")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "remainingAmount")})) + private Money remainingAmount; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "state")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "state")})) + private StateValue state; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "taxExcludedAmount")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "taxExcludedAmount")})) + private Money taxExcludedAmount; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "taxIncludedAmount")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "taxIncludedAmount")})) + private Money taxIncludedAmount; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "taxItem")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "taxItem", targetClass = TaxItem.class)})) + private List taxItem; + + public CustomerBill(String id) { + super(TYPE_CUSTOMER_BILL, id); + } +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBillOnDemand.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBillOnDemand.java new file mode 100644 index 00000000..06906b9c --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBillOnDemand.java @@ -0,0 +1,60 @@ +package org.fiware.tmforum.customer_bill.domain.customer_bill; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.fiware.tmforum.common.domain.EntityWithId; +import org.fiware.tmforum.customer_bill.domain.BillRef; +import org.fiware.tmforum.customer_bill.domain.BillingAccountRef; +import org.fiware.tmforum.customer_bill.domain.RelatedPartyRef; +import org.fiware.tmforum.customer_bill.domain.StateValues; +import org.fiware.tmforum.mapping.annotations.AttributeGetter; +import org.fiware.tmforum.mapping.annotations.AttributeSetter; +import org.fiware.tmforum.mapping.annotations.AttributeType; +import org.fiware.tmforum.mapping.annotations.MappingEnabled; + +import java.net.URL; +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@MappingEnabled(entityType = CustomerBillOnDemand.TYPE_CUSTOMER_BILL_ON_DEMAND) +public class CustomerBillOnDemand extends EntityWithId { + + public static final String TYPE_CUSTOMER_BILL_ON_DEMAND = "customer_bill_on_demand"; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "href")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "href")})) + private URL href; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "description")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "description")})) + private String description; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "lastUpdate")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "lastUpdate")})) + private String lastUpdate; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "name")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name")})) + private String name; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "billingAccount")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "billingAccount", targetClass = BillingAccountRef.class)})) + private BillingAccountRef billingAccount; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "customerBill")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "customerBill")})) + private BillRef customerBill; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.RELATIONSHIP, targetName = "relatedParty")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.RELATIONSHIP, targetName = "relatedParty", targetClass = RelatedPartyRef.class, fromProperties = true)})) + private RelatedPartyRef relatedParty; + + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "state")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "state")})) + private StateValues state; + + public CustomerBillOnDemand(String id) { + super(CustomerBillOnDemand.TYPE_CUSTOMER_BILL_ON_DEMAND, id); + } +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/AppliedCustomerBillingRateRepository.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/AppliedCustomerBillingRateRepository.java new file mode 100644 index 00000000..c5a51962 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/AppliedCustomerBillingRateRepository.java @@ -0,0 +1,63 @@ +package org.fiware.tmforum.customer_bill.repository; + +import io.reactivex.Maybe; +import io.reactivex.Single; +import org.fiware.ngsi.api.EntitiesApi; +import org.fiware.ngsi.model.EntityVO; +import org.fiware.tmforum.common.configuration.GeneralProperties; +import org.fiware.tmforum.common.repository.NgsiLdBaseRepository; +import org.fiware.tmforum.customer_bill.domain.customer_bill.AppliedCustomerBillingRate; +import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBill; +import org.fiware.tmforum.mapping.EntityVOMapper; +import org.fiware.tmforum.mapping.JavaObjectMapper; + +import javax.inject.Singleton; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +@Singleton +public class AppliedCustomerBillingRateRepository extends NgsiLdBaseRepository { + + private final EntityVOMapper entityVOMapper; + private final JavaObjectMapper javaObjectMapper; + + public AppliedCustomerBillingRateRepository(GeneralProperties generalProperties, EntitiesApi entitiesApi, EntityVOMapper entityVOMapper, JavaObjectMapper javaObjectMapper) { + super(generalProperties, entitiesApi); + this.entityVOMapper = entityVOMapper; + this.javaObjectMapper = javaObjectMapper; + } + + public Single> findAppliedCustomerBillingRates() { + return entitiesApi.queryEntities(generalProperties.getTenant(), + null, + null, + AppliedCustomerBillingRate.TYPE_APPLIED_CUSTOMER_BILLING_RATE, + null, + null, + null, + null, + null, + null, + null, + null, + null, + getLinkHeader()) + .map(List::stream) + .flatMap(entityVOStream -> zipToList(entityVOStream, AppliedCustomerBillingRate.class)); + } + + public Maybe getAppliedCustomerBillingRate(String id) { + return retrieveEntityById(URI.create(id)) + .flatMap(entityVO -> entityVOMapper.fromEntityVO(entityVO, AppliedCustomerBillingRate.class).toMaybe()); + } + + private Single> zipToList(Stream entityVOStream, Class targetClass) { + return Single.zip( + entityVOStream.map(entityVO -> entityVOMapper.fromEntityVO(entityVO, targetClass)).toList(), + oList -> Arrays.stream(oList).map(targetClass::cast).toList() + ); + } + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/CustomerBillOnDemandRepository.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/CustomerBillOnDemandRepository.java new file mode 100644 index 00000000..c61a4348 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/CustomerBillOnDemandRepository.java @@ -0,0 +1,67 @@ +package org.fiware.tmforum.customer_bill.repository; + +import io.reactivex.Completable; +import io.reactivex.Maybe; +import io.reactivex.Single; +import org.fiware.ngsi.api.EntitiesApi; +import org.fiware.ngsi.model.EntityVO; +import org.fiware.tmforum.common.configuration.GeneralProperties; +import org.fiware.tmforum.common.repository.NgsiLdBaseRepository; +import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBillOnDemand; +import org.fiware.tmforum.mapping.EntityVOMapper; +import org.fiware.tmforum.mapping.JavaObjectMapper; + +import javax.inject.Singleton; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +@Singleton +public class CustomerBillOnDemandRepository extends NgsiLdBaseRepository { + + private final EntityVOMapper entityVOMapper; + private final JavaObjectMapper javaObjectMapper; + + public CustomerBillOnDemandRepository(GeneralProperties generalProperties, EntitiesApi entitiesApi, EntityVOMapper entityVOMapper, JavaObjectMapper javaObjectMapper) { + super(generalProperties, entitiesApi); + this.entityVOMapper = entityVOMapper; + this.javaObjectMapper = javaObjectMapper; + } + + public Completable createCustomerBillOnDemand(CustomerBillOnDemand customerBillOnDemand) { + return createEntity(javaObjectMapper.toEntityVO(customerBillOnDemand), generalProperties.getTenant()); + } + + public Single> findCustomerBillsOnDemand() { + return entitiesApi.queryEntities(generalProperties.getTenant(), + null, + null, + CustomerBillOnDemand.TYPE_CUSTOMER_BILL_ON_DEMAND, + null, + null, + null, + null, + null, + null, + null, + null, + null, + getLinkHeader()) + .map(List::stream) + .flatMap(entityVOStream -> zipToList(entityVOStream, CustomerBillOnDemand.class)); + } + + public Maybe getCustomerBillOnDemand(String id) { + return retrieveEntityById(URI.create(id)) + .flatMap(entityVO -> entityVOMapper.fromEntityVO(entityVO, CustomerBillOnDemand.class).toMaybe()); + } + + private Single> zipToList(Stream entityVOStream, Class targetClass) { + return Single.zip( + entityVOStream.map(entityVO -> entityVOMapper.fromEntityVO(entityVO, targetClass)).toList(), + oList -> Arrays.stream(oList).map(targetClass::cast).toList() + ); + } + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/CustomerBillRepository.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/CustomerBillRepository.java new file mode 100644 index 00000000..3375f85d --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/repository/CustomerBillRepository.java @@ -0,0 +1,62 @@ +package org.fiware.tmforum.customer_bill.repository; + +import io.reactivex.Maybe; +import io.reactivex.Single; +import org.fiware.ngsi.api.EntitiesApi; +import org.fiware.ngsi.model.EntityVO; +import org.fiware.tmforum.common.configuration.GeneralProperties; +import org.fiware.tmforum.common.repository.NgsiLdBaseRepository; +import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBill; +import org.fiware.tmforum.mapping.EntityVOMapper; +import org.fiware.tmforum.mapping.JavaObjectMapper; + +import javax.inject.Singleton; +import java.net.URI; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Stream; + +@Singleton +public class CustomerBillRepository extends NgsiLdBaseRepository { + + private final EntityVOMapper entityVOMapper; + private final JavaObjectMapper javaObjectMapper; + + public CustomerBillRepository(GeneralProperties generalProperties, EntitiesApi entitiesApi, EntityVOMapper entityVOMapper, JavaObjectMapper javaObjectMapper) { + super(generalProperties, entitiesApi); + this.entityVOMapper = entityVOMapper; + this.javaObjectMapper = javaObjectMapper; + } + + public Single> findCustomerBills() { + return entitiesApi.queryEntities(generalProperties.getTenant(), + null, + null, + CustomerBill.TYPE_CUSTOMER_BILL, + null, + null, + null, + null, + null, + null, + null, + null, + null, + getLinkHeader()) + .map(List::stream) + .flatMap(entityVOStream -> zipToList(entityVOStream, CustomerBill.class)); + } + + public Maybe getCustomerBill(String id) { + return retrieveEntityById(URI.create(id)) + .flatMap(entityVO -> entityVOMapper.fromEntityVO(entityVO, CustomerBill.class).toMaybe()); + } + + private Single> zipToList(Stream entityVOStream, Class targetClass) { + return Single.zip( + entityVOStream.map(entityVO -> entityVOMapper.fromEntityVO(entityVO, targetClass)).toList(), + oList -> Arrays.stream(oList).map(targetClass::cast).toList() + ); + } + +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/AppliedCustomerBillingRateApiController.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/AppliedCustomerBillingRateApiController.java new file mode 100644 index 00000000..05447c7d --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/AppliedCustomerBillingRateApiController.java @@ -0,0 +1,42 @@ +package org.fiware.tmforum.customer_bill.rest; + +import io.micronaut.http.HttpResponse; +import io.micronaut.http.annotation.Controller; +import io.reactivex.Single; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fiware.customer_bill.api.AppliedCustomerBillingRateApi; +import org.fiware.customer_bill.model.AppliedCustomerBillingRateVO; +import org.fiware.tmforum.common.validation.ReferenceValidationService; +import org.fiware.tmforum.customer_bill.TMForumMapper; +import org.fiware.tmforum.customer_bill.repository.AppliedCustomerBillingRateRepository; + +import javax.annotation.Nullable; +import java.util.List; + +@Slf4j +@Controller +@RequiredArgsConstructor +public class AppliedCustomerBillingRateApiController implements AppliedCustomerBillingRateApi { + + private final TMForumMapper tmForumMapper; + private final AppliedCustomerBillingRateRepository billingRateRepository; + private final ReferenceValidationService validationService; + + + @Override + public Single>> listAppliedCustomerBillingRate(@Nullable String fields, @Nullable Integer offset, @Nullable Integer limit) { + return billingRateRepository.findAppliedCustomerBillingRates() + .map(List::stream) + .map(customerBillStream -> customerBillStream.map(tmForumMapper::map).toList()) + .map(HttpResponse::ok); + } + + @Override + public Single> retrieveAppliedCustomerBillingRate(String id, @Nullable String fields) { + return billingRateRepository.getAppliedCustomerBillingRate(id) + .map(tmForumMapper::map) + .toSingle() + .map(HttpResponse::ok); + } +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiController.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiController.java new file mode 100644 index 00000000..c8a9917f --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiController.java @@ -0,0 +1,50 @@ +package org.fiware.tmforum.customer_bill.rest; + +import io.micronaut.http.HttpResponse; +import io.micronaut.http.annotation.Controller; +import io.reactivex.Single; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fiware.customer_bill.api.CustomerBillApi; +import org.fiware.customer_bill.model.CustomerBillUpdateVO; +import org.fiware.customer_bill.model.CustomerBillVO; +import org.fiware.tmforum.common.validation.ReferenceValidationService; +import org.fiware.tmforum.customer_bill.TMForumMapper; +import org.fiware.tmforum.customer_bill.repository.CustomerBillRepository; + +import javax.annotation.Nullable; +import java.util.List; + +@Slf4j +@Controller +@RequiredArgsConstructor +public class CustomerBillApiController implements CustomerBillApi { + + private final TMForumMapper tmForumMapper; + + private final CustomerBillRepository customerBillRepository; + + private final ReferenceValidationService validationService; + + @Override + public Single>> listCustomerBill(@Nullable String fields, @Nullable Integer offset, @Nullable Integer limit) { + return customerBillRepository.findCustomerBills() + .map(List::stream) + .map(customerBillStream -> customerBillStream.map(tmForumMapper::map).toList()) + .map(HttpResponse::ok); + } + + @Override + public Single> patchCustomerBill(String id, CustomerBillUpdateVO customerBill) { + // implement proper patch + return null; + } + + @Override + public Single> retrieveCustomerBill(String id, @Nullable String fields) { + return customerBillRepository.getCustomerBill(id) + .map(tmForumMapper::map) + .toSingle() + .map(HttpResponse::ok); + } +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiController.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiController.java new file mode 100644 index 00000000..f8e880d1 --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiController.java @@ -0,0 +1,63 @@ +package org.fiware.tmforum.customer_bill.rest; + +import io.micronaut.http.HttpResponse; +import io.micronaut.http.annotation.Controller; +import io.reactivex.Single; +import io.reactivex.schedulers.Schedulers; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.fiware.customer_bill.api.CustomerBillOnDemandApi; +import org.fiware.customer_bill.model.CustomerBillOnDemandCreateVO; +import org.fiware.customer_bill.model.CustomerBillOnDemandVO; +import org.fiware.tmforum.common.exception.NonExistentReferenceException; +import org.fiware.tmforum.common.validation.ReferenceValidationService; +import org.fiware.tmforum.customer_bill.TMForumMapper; +import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBillOnDemand; +import org.fiware.tmforum.customer_bill.repository.CustomerBillOnDemandRepository; + +import javax.annotation.Nullable; +import java.util.List; + +@Slf4j +@Controller +@RequiredArgsConstructor +public class CustomerBillOnDemandApiController implements CustomerBillOnDemandApi { + + private final TMForumMapper tmForumMapper; + private final CustomerBillOnDemandRepository customerBillOnDemandRepository; + private final ReferenceValidationService validationService; + + + @Override + public Single> createCustomerBillOnDemand(CustomerBillOnDemandCreateVO customerBillOnDemandCreateVO) { + + CustomerBillOnDemandVO customerBillOnDemandVO = tmForumMapper.map(customerBillOnDemandCreateVO); + CustomerBillOnDemand customerBillOnDemand = tmForumMapper.map(customerBillOnDemandVO); + + Single customerBillOnDemandSingle = Single.just(customerBillOnDemand); + Single checkingSingle; + + return customerBillOnDemandSingle + .flatMap(customerBillOnDemandToCreate -> customerBillOnDemandRepository.createCustomerBillOnDemand(customerBillOnDemandToCreate).toSingleDefault(customerBillOnDemandToCreate)) + .cast(CustomerBillOnDemand.class) + .map(tmForumMapper::map) + .subscribeOn(Schedulers.io()) + .map(HttpResponse::created); + } + + @Override + public Single>> listCustomerBillOnDemand(@Nullable String fields, @Nullable Integer offset, @Nullable Integer limit) { + return customerBillOnDemandRepository.findCustomerBillsOnDemand() + .map(List::stream) + .map(customerBillOnDemandStream -> customerBillOnDemandStream.map(tmForumMapper::map).toList()) + .map(HttpResponse::ok); + } + + @Override + public Single> retrieveCustomerBillOnDemand(String id, @Nullable String fields) { + return customerBillOnDemandRepository.getCustomerBillOnDemand(id) + .map(tmForumMapper::map) + .toSingle() + .map(HttpResponse::ok); + } +} diff --git a/customer-bill/src/main/resources/application.yaml b/customer-bill/src/main/resources/application.yaml new file mode 100644 index 00000000..0affe880 --- /dev/null +++ b/customer-bill/src/main/resources/application.yaml @@ -0,0 +1,44 @@ +micronaut: + application: + name: ${project.artifactId} + + caches: + entities: + maximumSize: 1000 + + server: + port: 8080 + + metrics: + enabled: true + export: + prometheus: + step: PT2s + descriptions: false + + http: + services: + read-timeout: 30s + ngsi: + path: ngsi-ld/v1 + url: http://localhost:1026 + read-timeout: 30 +--- +jackson: + serialization: + writeDatesAsTimestamps: false +--- +endpoints: + metrics: + enabled: true + health: + enabled: true + +--- +loggers: + levels: + ROOT: TRACE + +--- +general: + contextUrl: https://smartdatamodels.org/context.jsonld \ No newline at end of file diff --git a/customer-bill/src/main/resources/logback.xml b/customer-bill/src/main/resources/logback.xml new file mode 100644 index 00000000..f075e861 --- /dev/null +++ b/customer-bill/src/main/resources/logback.xml @@ -0,0 +1,16 @@ + + + + true + + + %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n + + + + + + + + \ No newline at end of file diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java index 9a4839ae..60f03e6d 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/customer/Customer.java @@ -58,7 +58,7 @@ public class Customer extends EntityWithId { @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.RELATIONSHIP, targetName = "engagedParty")})) @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.RELATIONSHIP, targetName = "engagedParty", targetClass = RelatedParty.class, fromProperties = true)})) - private RelatedPartyVO engagedParty; + private RelatedParty engagedParty; @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "paymentMethod")})) @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.RELATIONSHIP_LIST, targetName = "paymentMethod", targetClass = PaymentMethodRef.class, fromProperties = true)})) diff --git a/pom.xml b/pom.xml index 10e74876..6fd14764 100644 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,7 @@ common party customer + customer-bill From 7e41d304d77bb07d4e2cc969b811ba7ef9f16fde Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Mon, 12 Sep 2022 15:32:26 +0100 Subject: [PATCH 10/16] Adding first IT for CustomerBilling Management API --- .../customer_bill/CustomerBillApiIT.java | 71 +++++++++++++++++++ .../src/test/resources/application.yaml | 38 ++++++++++ customer-bill/src/test/resources/logback.xml | 16 +++++ 3 files changed, 125 insertions(+) create mode 100644 customer-bill/src/test/java/org/fiware/tmforum/customer_bill/CustomerBillApiIT.java create mode 100644 customer-bill/src/test/resources/application.yaml create mode 100644 customer-bill/src/test/resources/logback.xml diff --git a/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/CustomerBillApiIT.java b/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/CustomerBillApiIT.java new file mode 100644 index 00000000..a9d9ed4d --- /dev/null +++ b/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/CustomerBillApiIT.java @@ -0,0 +1,71 @@ +package org.fiware.tmforum.customer_bill; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.micronaut.test.extensions.junit5.annotation.MicronautTest; +import lombok.RequiredArgsConstructor; +import org.fiware.customer_bill.model.CustomerBillOnDemandCreateVO; +import org.fiware.customer_bill.model.CustomerBillOnDemandVO; +import org.fiware.customer_bill.model.StateValuesVO; +import org.fiware.tmforum.customer_bill.rest.AppliedCustomerBillingRateApiController; +import org.fiware.tmforum.customer_bill.rest.CustomerBillApiController; +import org.fiware.tmforum.customer_bill.rest.CustomerBillOnDemandApiController; +import org.junit.jupiter.api.Test; + +import java.text.ParseException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@RequiredArgsConstructor +@MicronautTest(packages = {"org.fiware.tmforum.customer_bill"}) +public class CustomerBillApiIT { + + private final ObjectMapper objectMapper; + private final CustomerBillApiController customerBillApiController; + private final CustomerBillOnDemandApiController customerBillOnDemandApiController; + private final AppliedCustomerBillingRateApiController appliedCustomerBillingRateApiController; + + @Test + void test() throws JsonProcessingException, ParseException { + // Test CustomerBillOnDemandApi create + CustomerBillOnDemandCreateVO myFancyCustomerBillOnDemandCreate = getCustomerBillOnDemand(); + HttpResponse myFancyCustomerBillOnDemandCreateResponse = + customerBillOnDemandApiController.createCustomerBillOnDemand(myFancyCustomerBillOnDemandCreate) + .blockingGet(); + assertEquals(HttpStatus.CREATED, + myFancyCustomerBillOnDemandCreateResponse.getStatus(), + "CustomerBillOnDemand should have been created."); + CustomerBillOnDemandVO myFancyCustomerBillOnDemand = myFancyCustomerBillOnDemandCreateResponse.body(); + + // Test CustomerBillOnDemandApi retrieve + HttpResponse customerBillOnDemandResponse = + customerBillOnDemandApiController.retrieveCustomerBillOnDemand(myFancyCustomerBillOnDemand.getId(), null) + .blockingGet(); + assertEquals(HttpStatus.OK, + customerBillOnDemandResponse.getStatus(), + "A CustomerBillOnDemand response is expected."); + assertTrue(customerBillOnDemandResponse.getBody().isPresent(), + "A CustomerBillOnDemand response is expected."); + assertEquals(myFancyCustomerBillOnDemand, + customerBillOnDemandResponse.getBody().get(), + "The full CustomerBillOnDemand should be retrieved"); + + // Test CustomerBillApi --> no create? + + // Test AppliedCustomerBillingRateApi --> no create? + } + + private CustomerBillOnDemandCreateVO getCustomerBillOnDemand() throws JsonProcessingException { + CustomerBillOnDemandCreateVO customerBillOnDemand = new CustomerBillOnDemandCreateVO(); + + customerBillOnDemand.setDescription("My fancy description of CustomerBillOnDemand"); + customerBillOnDemand.setName("My fancy name"); + customerBillOnDemand.setLastUpdate("2022-03-04-08:00:00"); + customerBillOnDemand.setState(StateValuesVO.DONE); + + return customerBillOnDemand; + } +} diff --git a/customer-bill/src/test/resources/application.yaml b/customer-bill/src/test/resources/application.yaml new file mode 100644 index 00000000..52f52f3f --- /dev/null +++ b/customer-bill/src/test/resources/application.yaml @@ -0,0 +1,38 @@ +micronaut: + caches: + entities: + maximumSize: 1000 + + metrics: + enabled: false + export: + prometheus: + step: PT2s + descriptions: false + + http: + services: + read-timeout: 30s + ngsi: + path: ngsi-ld/v1 + url: http://localhost:1026 + read-timeout: 30 +--- +jackson: + serialization: + writeDatesAsTimestamps: false +--- +endpoints: + metrics: + enabled: false + health: + enabled: false + +--- +loggers: + levels: + ROOT: TRACE + +--- +general: + contextUrl: https://smartdatamodels.org/context.jsonld \ No newline at end of file diff --git a/customer-bill/src/test/resources/logback.xml b/customer-bill/src/test/resources/logback.xml new file mode 100644 index 00000000..f075e861 --- /dev/null +++ b/customer-bill/src/test/resources/logback.xml @@ -0,0 +1,16 @@ + + + + true + + + %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n + + + + + + + + \ No newline at end of file From 89c3a67c7d24fd41ccb4d7f4f9abe0e4113b2e6e Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Mon, 12 Sep 2022 15:36:38 +0100 Subject: [PATCH 11/16] Extend Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dc0d6b47..e8c529ca 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ The api-implementations are inside modules, producing jar-files and oci-containe Current api-implementations: - [party-management-api](party) - implementation of the party-management-api - [customer-management-api](customer) - implementation of the customer-management-api +- [customer-bill-management-api](customer-bill) - implementation of the customer-bill-management-api The project also contains 2 non-module folders: - [api](api) - contains the [OpenApi-Specifications](https://spec.openapis.org/oas/v3.1.0) used by the project. Beside the TMForum-Apis it also contains the specification of the NGSI-LD API. From 4a05afdf1a41afd8140b3efa1dc024ed858c566b Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Tue, 13 Sep 2022 14:14:02 +0100 Subject: [PATCH 12/16] * Extend CustomerBill tests * Extend tests with related parties * Fix BillingAccountRef * Add validation for CustomerBillOnDemand create API * Add TODOs --- .../customer_bill/domain/RelatedPartyRef.java | 10 ++- .../customer_bill/CustomerBillOnDemand.java | 4 +- ...CustomerBillOnDemandCreationException.java | 15 ++++ .../rest/CustomerBillApiController.java | 2 +- .../CustomerBillOnDemandApiController.java | 28 +++++++ .../customer_bill/CustomerBillApiIT.java | 63 +++++++++++---- .../tmforum/customer/domain/RelatedParty.java | 3 + .../customer/rest/CustomerApiController.java | 21 ++++- .../tmforum/customer/CustomerApiIT.java | 76 +++++++++++++++---- 9 files changed, 188 insertions(+), 34 deletions(-) create mode 100644 customer-bill/src/main/java/org/fiware/tmforum/customer_bill/exception/CustomerBillOnDemandCreationException.java diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RelatedPartyRef.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RelatedPartyRef.java index 9c5f6337..80bff6d8 100644 --- a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RelatedPartyRef.java +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/RelatedPartyRef.java @@ -3,7 +3,9 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; +import org.fiware.tmforum.customer_bill.domain.customer_bill.AppliedCustomerBillingRate; import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBill; +import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBillOnDemand; import org.fiware.tmforum.mapping.annotations.*; import java.util.List; @@ -27,7 +29,13 @@ public RelatedPartyRef(String id) { @Override @Ignore public List getReferencedTypes() { - return List.of(CustomerBill.TYPE_CUSTOMER_BILL); + /** + * TODO: Check if list is correct + */ + return List.of( + CustomerBill.TYPE_CUSTOMER_BILL, + CustomerBillOnDemand.TYPE_CUSTOMER_BILL_ON_DEMAND, + AppliedCustomerBillingRate.TYPE_APPLIED_CUSTOMER_BILLING_RATE); } } diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBillOnDemand.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBillOnDemand.java index 06906b9c..528111f5 100644 --- a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBillOnDemand.java +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/domain/customer_bill/CustomerBillOnDemand.java @@ -38,8 +38,8 @@ public class CustomerBillOnDemand extends EntityWithId { @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "name")})) private String name; - @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY_LIST, targetName = "billingAccount")})) - @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY_LIST, targetName = "billingAccount", targetClass = BillingAccountRef.class)})) + @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "billingAccount")})) + @Setter(onMethod = @__({@AttributeSetter(value = AttributeType.PROPERTY, targetName = "billingAccount")})) private BillingAccountRef billingAccount; @Getter(onMethod = @__({@AttributeGetter(value = AttributeType.PROPERTY, targetName = "customerBill")})) diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/exception/CustomerBillOnDemandCreationException.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/exception/CustomerBillOnDemandCreationException.java new file mode 100644 index 00000000..e0293b0a --- /dev/null +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/exception/CustomerBillOnDemandCreationException.java @@ -0,0 +1,15 @@ +package org.fiware.tmforum.customer_bill.exception; + +/** + * Exception to be thrown in case a customer bill on demand could not have been created. + */ +public class CustomerBillOnDemandCreationException extends RuntimeException { + + public CustomerBillOnDemandCreationException(String message) { + super(message); + } + + public CustomerBillOnDemandCreationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiController.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiController.java index c8a9917f..22483bea 100644 --- a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiController.java +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiController.java @@ -36,7 +36,7 @@ public Single>> listCustomerBill(@Nullable Str @Override public Single> patchCustomerBill(String id, CustomerBillUpdateVO customerBill) { - // implement proper patch + // TODO: implement proper patch return null; } diff --git a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiController.java b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiController.java index f8e880d1..44a30a1a 100644 --- a/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiController.java +++ b/customer-bill/src/main/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiController.java @@ -13,6 +13,7 @@ import org.fiware.tmforum.common.validation.ReferenceValidationService; import org.fiware.tmforum.customer_bill.TMForumMapper; import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBillOnDemand; +import org.fiware.tmforum.customer_bill.exception.CustomerBillOnDemandCreationException; import org.fiware.tmforum.customer_bill.repository.CustomerBillOnDemandRepository; import javax.annotation.Nullable; @@ -37,6 +38,33 @@ public Single> createCustomerBillOnDemand(C Single customerBillOnDemandSingle = Single.just(customerBillOnDemand); Single checkingSingle; + /** + * Validate references + * + * TODO: Need to check if and how to validate: + * - BillRef + * - BillingAccountRef + * --> also check if these should extend RefEntity and what are allowed ref types in this case + * + * TODO: Check if relatedParty object is correct + * - what are allowed ref types? + */ + try { + if (customerBillOnDemand.getRelatedParty() != null) { + checkingSingle = + validationService.getCheckingSingleOrThrow( + List.of(customerBillOnDemand.getRelatedParty()), + customerBillOnDemand); + customerBillOnDemandSingle = + Single.zip(customerBillOnDemandSingle, checkingSingle, (p1, p2) -> p1); + } + } catch (NonExistentReferenceException e) { + throw new CustomerBillOnDemandCreationException( + String.format("Was not able to create customer bill on demand %s", + customerBillOnDemand.getId()), + e); + } + return customerBillOnDemandSingle .flatMap(customerBillOnDemandToCreate -> customerBillOnDemandRepository.createCustomerBillOnDemand(customerBillOnDemandToCreate).toSingleDefault(customerBillOnDemandToCreate)) .cast(CustomerBillOnDemand.class) diff --git a/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/CustomerBillApiIT.java b/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/CustomerBillApiIT.java index a9d9ed4d..2aee0745 100644 --- a/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/CustomerBillApiIT.java +++ b/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/CustomerBillApiIT.java @@ -6,9 +6,7 @@ import io.micronaut.http.HttpStatus; import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import lombok.RequiredArgsConstructor; -import org.fiware.customer_bill.model.CustomerBillOnDemandCreateVO; -import org.fiware.customer_bill.model.CustomerBillOnDemandVO; -import org.fiware.customer_bill.model.StateValuesVO; +import org.fiware.customer_bill.model.*; import org.fiware.tmforum.customer_bill.rest.AppliedCustomerBillingRateApiController; import org.fiware.tmforum.customer_bill.rest.CustomerBillApiController; import org.fiware.tmforum.customer_bill.rest.CustomerBillOnDemandApiController; @@ -19,6 +17,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +/** + * Tests for Customer Bill Management API + * + * TODO: + * - Implement EventsSubscriptionApi + Tests + * - Implement TimeTypeConverterRegistrar + Tests + * - check how to create entities via CustomerBillApi and AppliedCustomerBillingRateApi + */ @RequiredArgsConstructor @MicronautTest(packages = {"org.fiware.tmforum.customer_bill"}) public class CustomerBillApiIT { @@ -31,7 +37,8 @@ public class CustomerBillApiIT { @Test void test() throws JsonProcessingException, ParseException { // Test CustomerBillOnDemandApi create - CustomerBillOnDemandCreateVO myFancyCustomerBillOnDemandCreate = getCustomerBillOnDemand(); + CustomerBillOnDemandCreateVO myFancyCustomerBillOnDemandCreate = + getCustomerBillOnDemand("My fancy first CustomerBillOnDemand", null); HttpResponse myFancyCustomerBillOnDemandCreateResponse = customerBillOnDemandApiController.createCustomerBillOnDemand(myFancyCustomerBillOnDemandCreate) .blockingGet(); @@ -40,32 +47,60 @@ void test() throws JsonProcessingException, ParseException { "CustomerBillOnDemand should have been created."); CustomerBillOnDemandVO myFancyCustomerBillOnDemand = myFancyCustomerBillOnDemandCreateResponse.body(); - // Test CustomerBillOnDemandApi retrieve + // Test CustomerBillOnDemand 2nd create with related party + RelatedPartyRefVO relatedPartyRefVO = new RelatedPartyRefVO(); + relatedPartyRefVO.setName("My related party ref"); + relatedPartyRefVO.setId(myFancyCustomerBillOnDemand.getId()); + relatedPartyRefVO.setRole("My related party ref role"); + CustomerBillOnDemandCreateVO myFancySecondCustomerBillOnDemandCreate = + getCustomerBillOnDemand("My fancy 2nd CustomerBillOnDemand", relatedPartyRefVO); + HttpResponse myFancySecondCustomerBillOnDemandCreateResponse = + customerBillOnDemandApiController.createCustomerBillOnDemand(myFancySecondCustomerBillOnDemandCreate) + .blockingGet(); + assertEquals(HttpStatus.CREATED, + myFancySecondCustomerBillOnDemandCreateResponse.getStatus(), + "2nd CustomerBillOnDemand should have been created."); + CustomerBillOnDemandVO myFancySecondCustomerBillOnDemand = myFancySecondCustomerBillOnDemandCreateResponse.body(); + + // Test CustomerBillOnDemandApi retrieve of 2nd CustomerBillOnDemand HttpResponse customerBillOnDemandResponse = - customerBillOnDemandApiController.retrieveCustomerBillOnDemand(myFancyCustomerBillOnDemand.getId(), null) + customerBillOnDemandApiController.retrieveCustomerBillOnDemand( + myFancySecondCustomerBillOnDemand.getId(), null) .blockingGet(); assertEquals(HttpStatus.OK, customerBillOnDemandResponse.getStatus(), - "A CustomerBillOnDemand response is expected."); + "A CustomerBillOnDemand response is expected with status OK."); assertTrue(customerBillOnDemandResponse.getBody().isPresent(), - "A CustomerBillOnDemand response is expected."); - assertEquals(myFancyCustomerBillOnDemand, + "A CustomerBillOnDemand response is expected with body present."); + assertEquals(myFancySecondCustomerBillOnDemand, customerBillOnDemandResponse.getBody().get(), - "The full CustomerBillOnDemand should be retrieved"); + "The full 2nd CustomerBillOnDemand should be retrieved"); - // Test CustomerBillApi --> no create? + // TODO: Test CustomerBillApi --> no create? - // Test AppliedCustomerBillingRateApi --> no create? + // TODO: Test AppliedCustomerBillingRateApi --> no create? } - private CustomerBillOnDemandCreateVO getCustomerBillOnDemand() throws JsonProcessingException { + private CustomerBillOnDemandCreateVO getCustomerBillOnDemand(String name, RelatedPartyRefVO relatedPartyRefVO) throws JsonProcessingException { CustomerBillOnDemandCreateVO customerBillOnDemand = new CustomerBillOnDemandCreateVO(); customerBillOnDemand.setDescription("My fancy description of CustomerBillOnDemand"); - customerBillOnDemand.setName("My fancy name"); + customerBillOnDemand.setName(name); customerBillOnDemand.setLastUpdate("2022-03-04-08:00:00"); + + BillingAccountRefVO billingAccountRefVO = new BillingAccountRefVO(); + billingAccountRefVO.setName("Fancy billing account ref"); + customerBillOnDemand.setBillingAccount(billingAccountRefVO); + + BillRefVO billRefVO = new BillRefVO(); + customerBillOnDemand.setCustomerBill(billRefVO); + customerBillOnDemand.setState(StateValuesVO.DONE); + if (relatedPartyRefVO != null) { + customerBillOnDemand.setRelatedParty(relatedPartyRefVO); + } + return customerBillOnDemand; } } diff --git a/customer/src/main/java/org/fiware/tmforum/customer/domain/RelatedParty.java b/customer/src/main/java/org/fiware/tmforum/customer/domain/RelatedParty.java index fa292423..66dcf5d2 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/domain/RelatedParty.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/domain/RelatedParty.java @@ -27,6 +27,9 @@ public RelatedParty(String id) { @Override @Ignore public List getReferencedTypes() { + /** + * TODO: Check if list is correct + */ return List.of(Customer.TYPE_CUSTOMER); } diff --git a/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java b/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java index 8387defc..dab24606 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java @@ -37,11 +37,30 @@ public Single> createCustomer(CustomerCreateVO customer Single customerSingle = Single.just(customer); Single checkingSingle; + /** + * Validate references + * + * TODO: Need to check if and how to validate: + * - PaymentMethodRef + * - AgreementRef + * - AccountRef + * --> also check if these should extend RefEntity and what are allowed ref types in this case + * + * TODO: Check if relatedParty and engagedParty object is correct + * - what are allowed ref types? + */ try { if (customer.getRelatedParty() != null && !customer.getRelatedParty().isEmpty()) { checkingSingle = validationService.getCheckingSingleOrThrow(customer.getRelatedParty(), customer); customerSingle = Single.zip(customerSingle, checkingSingle, (p1, p2) -> p1); } + if (customer.getEngagedParty() != null) { + checkingSingle = + validationService.getCheckingSingleOrThrow( + List.of(customer.getEngagedParty()), + customer); + customerSingle = Single.zip(customerSingle, checkingSingle, (p1, p2) -> p1); + } } catch (NonExistentReferenceException e) { throw new CustomerCreationException(String.format("Was not able to create customer %s", customer.getId()), e); } @@ -69,7 +88,7 @@ public Single>> listCustomer(@Nullable String fiel @Override public Single> patchCustomer(String id, CustomerUpdateVO customer) { - // implement proper patch + // TODO: implement proper patch return null; } diff --git a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java index ff3ba70d..3b4642de 100644 --- a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java +++ b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java @@ -18,6 +18,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +/** + * Tests for Customer Management API + * + * TODO: + * - Implement EventsSubscriptionApi + Tests + * - Implement NotificationListenersClientSideApi + Tests + * - Implement TimeTypeConverterRegistrar + Tests + */ @RequiredArgsConstructor @MicronautTest(packages = {"org.fiware.tmforum.customer"}) class CustomerApiIT { @@ -27,29 +35,58 @@ class CustomerApiIT { @Test void test() throws JsonProcessingException, ParseException { - CustomerCreateVO myFancyCustomerCreate = getMyFancyCustomer(); + CustomerCreateVO myFancyFirstCustomerCreate = getMyFancyCustomer( + "My Fancy first Customer", null + ); // Test create - HttpResponse myFancyCustomerCreateResponse = customerApiController.createCustomer(myFancyCustomerCreate).blockingGet(); - assertEquals(HttpStatus.CREATED, myFancyCustomerCreateResponse.getStatus(), "Customer should have been created"); - CustomerVO myFancyCustomer = myFancyCustomerCreateResponse.body(); - - // Test retrieve - HttpResponse customerVOHttpResponse = customerApiController.retrieveCustomer(myFancyCustomer.getId(), null).blockingGet(); - assertEquals(HttpStatus.OK, customerVOHttpResponse.getStatus(), "A customer response is expected."); + HttpResponse myFancyCustomerCreateResponse = + customerApiController.createCustomer(myFancyFirstCustomerCreate).blockingGet(); + assertEquals(HttpStatus.CREATED, + myFancyCustomerCreateResponse.getStatus(), + "Customer should have been created"); + CustomerVO myFancyFirstCustomer = myFancyCustomerCreateResponse.body(); + + // Test create 2nd customer with related party + RelatedPartyVO relatedPartyVO = new RelatedPartyVO(); + relatedPartyVO.setId(myFancyFirstCustomer.getId()); + relatedPartyVO.setRole("My fancy related party role"); + relatedPartyVO.setName("My fancy related party"); + CustomerCreateVO myFancySecondCustomerCreate = getMyFancyCustomer( + "My fancy 2nd customer", + relatedPartyVO + ); + HttpResponse myFancySecondCustomerCreateResponse = + customerApiController.createCustomer(myFancySecondCustomerCreate).blockingGet(); + assertEquals(HttpStatus.CREATED, + myFancySecondCustomerCreateResponse.getStatus(), + "2nd Customer should have been created"); + CustomerVO myFancySecondCustomer = myFancySecondCustomerCreateResponse.body(); + + // Test retrieve of 2nd customer + HttpResponse customerVOHttpResponse = + customerApiController.retrieveCustomer(myFancySecondCustomer.getId(), null).blockingGet(); + assertEquals(HttpStatus.OK, + customerVOHttpResponse.getStatus(), + "A customer response is expected."); assertTrue(customerVOHttpResponse.getBody().isPresent(), "A customer response is expected."); - assertEquals(myFancyCustomer, customerVOHttpResponse.getBody().get(), "The full customer should be retrieved"); + assertEquals(myFancySecondCustomer, + customerVOHttpResponse.getBody().get(), + "The full 2nd customer should be retrieved"); - // Test delete - HttpResponse customerDeleteResponse = customerApiController.deleteCustomer(myFancyCustomer.getId()).blockingGet(); - assertEquals(HttpStatus.NO_CONTENT, customerDeleteResponse.getStatus(), "A NO_CONTENT response is expected"); + // Test delete 2nd customer + HttpResponse customerDeleteResponse = + customerApiController.deleteCustomer(myFancySecondCustomer.getId()).blockingGet(); + assertEquals(HttpStatus.NO_CONTENT, + customerDeleteResponse.getStatus(), + "A NO_CONTENT response is expected"); } - private CustomerCreateVO getMyFancyCustomer() throws JsonProcessingException { + private CustomerCreateVO getMyFancyCustomer(String name, RelatedPartyVO relatedPartyVO) throws JsonProcessingException { CustomerCreateVO customerVO = new CustomerCreateVO(); - customerVO.setName("My Fancy Customer"); + customerVO.setName(name); customerVO.setStatus("My fancy status"); customerVO.setStatusReason("Fancy reason for my fancy status"); @@ -69,7 +106,11 @@ private CustomerCreateVO getMyFancyCustomer() throws JsonProcessingException { contactMediumVO.setMediumType("postal address"); contactMediumVO.setPreferred(true); contactMediumVO.setCharacteristic(mediumCharacteristicVO); - contactMediumVO.setValidFor(new TimePeriodVO().startDateTime(Instant.now()).endDateTime(Instant.now().plus(Duration.of(10, ChronoUnit.DAYS)))); + contactMediumVO.setValidFor( + new TimePeriodVO() + .startDateTime(Instant.now()) + .endDateTime(Instant.now() + .plus(Duration.of(10, ChronoUnit.DAYS)))); AccountRefVO accountRefVO = new AccountRefVO(); accountRefVO.setId("urn:ngsi-ld:AccountRef:MyAccountRef001"); @@ -94,6 +135,11 @@ private CustomerCreateVO getMyFancyCustomer() throws JsonProcessingException { paymentMethodRefVO.setId("urn:ngsi-ld:PaymentMethodRef:MyPaymentMethodRef001"); paymentMethodRefVO.setName("My PaymentMethodRef name"); + if (relatedPartyVO != null) { + customerVO.setRelatedParty(List.of(relatedPartyVO)); + customerVO.setEngagedParty(relatedPartyVO); + } + customerVO.setContactMedium(List.of(contactMediumVO)); customerVO.setAccount(List.of(accountRefVO)); customerVO.setAgreement(List.of(agreementRefVO)); From e85a68dd900361bea7cd909a4d80bbec63898b85 Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Wed, 14 Sep 2022 15:59:39 +0100 Subject: [PATCH 13/16] Extend unit tests for customer API controller --- .../tmforum/customer/CustomerApiIT.java | 4 + .../rest/CustomerApiControllerTest.java | 74 ++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java index 3b4642de..a2282451 100644 --- a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java +++ b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java @@ -74,6 +74,10 @@ void test() throws JsonProcessingException, ParseException { customerVOHttpResponse.getBody().get(), "The full 2nd customer should be retrieved"); + // TODO: implement test for patch + + // TODO: implement test for listCustomer + // Test delete 2nd customer HttpResponse customerDeleteResponse = customerApiController.deleteCustomer(myFancySecondCustomer.getId()).blockingGet(); diff --git a/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java b/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java index 5a9b1de8..a585b05b 100644 --- a/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java +++ b/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java @@ -2,6 +2,8 @@ import io.micronaut.http.HttpResponse; import io.micronaut.http.HttpStatus; +import io.reactivex.Completable; +import io.reactivex.Maybe; import io.reactivex.Single; import org.fiware.customer.model.*; import org.fiware.tmforum.common.repository.ReferencesRepository; @@ -14,10 +16,23 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.reactivestreams.Publisher; + +import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Matchers.*; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +/** + * Unit Tests for CustomerApiController + * + * TODO: + * * Tests for listCustomer + * * Tests for delete + */ public class CustomerApiControllerTest { private final TMForumMapper tmForumMapper = new TMForumMapperImpl(); @@ -31,11 +46,68 @@ public void setup() { customerApiController = new CustomerApiController(tmForumMapper, customerRepository, validationService); } + private CustomerVO getCustomer(CustomerVO customer) { + return customer; + } + @DisplayName("Customer created") @Test void testCreateCustomer() { CustomerCreateVO customerCreateVO = new CustomerCreateVO(); + customerCreateVO.setName("Customer Name"); + CustomerVO customerMockVO = tmForumMapper.map(customerCreateVO); + + RelatedPartyVO relatedPartyVO = new RelatedPartyVO(); + relatedPartyVO.setName("Related party name"); + relatedPartyVO.setRole("Related party role"); + relatedPartyVO.setId("id1"); + customerCreateVO.setRelatedParty(List.of(relatedPartyVO)); + customerCreateVO.setEngagedParty(relatedPartyVO); + + // Stub customer repo create + when(customerRepository.createCustomer(anyObject())) + .thenReturn(Completable.fromAction(() -> getCustomer(customerMockVO))); + + // Stub references repo ref exists + when(referencesRepository.referenceExists(anyString(), anyList())) + .thenReturn(Maybe.just(relatedPartyVO)); + + Single> singleResponse = + customerApiController.createCustomer(customerCreateVO); + CustomerVO customerResponseVO = singleResponse.blockingGet().body(); + + assertEquals(HttpStatus.CREATED, + singleResponse.blockingGet().getStatus(), + "A customer response with status CREATED is expected."); + assertTrue(singleResponse.blockingGet().getBody().isPresent(), + "A customer response contains object"); + assertEquals(customerCreateVO.getName(), + customerResponseVO.getName(), + "Returned customer should have equal name compared to the created one"); + } + + @DisplayName("Customer received") + @Test + void testReceiveCustomer() { + CustomerVO customerVO = new CustomerVO(); + customerVO.setName("Customer Name"); + customerVO.setId("id1"); + Customer customer = tmForumMapper.map(customerVO); + + // Stub customer repo receive + when(customerRepository.getCustomer("id1")) + .thenReturn(Maybe.just(customer)); + + // Retrieve customer + HttpResponse customerVOHttpResponse = + customerApiController.retrieveCustomer("id1", null).blockingGet(); + assertEquals(HttpStatus.OK, + customerVOHttpResponse.getStatus(), + "A customer response has OK status"); + assertTrue(customerVOHttpResponse.getBody().isPresent(), "A customer response has object body."); + assertEquals(customerVO, + customerVOHttpResponse.getBody().get(), + "The same customer was returned"); - Single> singleResponse = customerApiController.createCustomer(customerCreateVO); } } From 5406e5251487571ca300f8a36b93e6a9b2ec680f Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Wed, 14 Sep 2022 16:39:35 +0100 Subject: [PATCH 14/16] Add unit tests for customer bill API controllers --- .../rest/CustomerBillApiControllerTest.java | 66 ++++++++++ ...CustomerBillOnDemandApiControllerTest.java | 118 ++++++++++++++++++ .../rest/CustomerApiControllerTest.java | 5 +- 3 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 customer-bill/src/test/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiControllerTest.java create mode 100644 customer-bill/src/test/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiControllerTest.java diff --git a/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiControllerTest.java b/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiControllerTest.java new file mode 100644 index 00000000..8d364b00 --- /dev/null +++ b/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/rest/CustomerBillApiControllerTest.java @@ -0,0 +1,66 @@ +package org.fiware.tmforum.customer_bill.rest; + +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.reactivex.Maybe; +import org.fiware.customer_bill.model.CustomerBillVO; +import org.fiware.tmforum.common.repository.ReferencesRepository; +import org.fiware.tmforum.common.validation.ReferenceValidationService; +import org.fiware.tmforum.customer_bill.TMForumMapper; +import org.fiware.tmforum.customer_bill.TMForumMapperImpl; +import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBill; +import org.fiware.tmforum.customer_bill.repository.CustomerBillRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Unit Tests for CustomerBillApiController + * + * TODO: + * - Tests for listCustomerBill + * - Tests for patch + */ +public class CustomerBillApiControllerTest { + + private final TMForumMapper tmForumMapper = new TMForumMapperImpl(); + private final CustomerBillRepository customerBillRepository = mock(CustomerBillRepository.class); + private final ReferencesRepository referencesRepository = mock(ReferencesRepository.class); + private final ReferenceValidationService validationService = new ReferenceValidationService(referencesRepository); + private CustomerBillApiController customerBillApiController; + + @BeforeEach + public void setup() { + customerBillApiController = new CustomerBillApiController(tmForumMapper, customerBillRepository, validationService); + } + + @DisplayName("Customer bill received") + @Test + void testReceiveCustomerBill() { + CustomerBillVO customerBillVO = new CustomerBillVO(); + customerBillVO.setBillNo("1234"); + customerBillVO.setId("id1"); + CustomerBill customerBill = tmForumMapper.map(customerBillVO); + + // Stub customer bill repo receive + when(customerBillRepository.getCustomerBill("id1")) + .thenReturn(Maybe.just(customerBill)); + + // Retrieve customer + HttpResponse customerBillVOHttpResponse = + customerBillApiController.retrieveCustomerBill("id1", null).blockingGet(); + assertEquals(HttpStatus.OK, + customerBillVOHttpResponse.getStatus(), + "A customer bill response has OK status"); + assertTrue(customerBillVOHttpResponse.getBody().isPresent(), "A customer bill response has object body."); + assertEquals(customerBillVO, + customerBillVOHttpResponse.getBody().get(), + "The same customer bill was returned"); + + } +} diff --git a/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiControllerTest.java b/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiControllerTest.java new file mode 100644 index 00000000..d279c6ed --- /dev/null +++ b/customer-bill/src/test/java/org/fiware/tmforum/customer_bill/rest/CustomerBillOnDemandApiControllerTest.java @@ -0,0 +1,118 @@ +package org.fiware.tmforum.customer_bill.rest; + +import io.micronaut.http.HttpResponse; +import io.micronaut.http.HttpStatus; +import io.reactivex.Completable; +import io.reactivex.Maybe; +import io.reactivex.Single; +import org.fiware.customer_bill.model.CustomerBillOnDemandCreateVO; +import org.fiware.customer_bill.model.CustomerBillOnDemandVO; +import org.fiware.customer_bill.model.CustomerBillVO; +import org.fiware.customer_bill.model.RelatedPartyRefVO; +import org.fiware.tmforum.common.repository.ReferencesRepository; +import org.fiware.tmforum.common.validation.ReferenceValidationService; +import org.fiware.tmforum.customer_bill.TMForumMapper; +import org.fiware.tmforum.customer_bill.TMForumMapperImpl; +import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBill; +import org.fiware.tmforum.customer_bill.domain.customer_bill.CustomerBillOnDemand; +import org.fiware.tmforum.customer_bill.repository.CustomerBillOnDemandRepository; +import org.fiware.tmforum.customer_bill.repository.CustomerBillRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Unit Tests for CustomerBillOnDemandApiController + * + * TODO: + * - Tests for listCustomerBillOnDemand + */ +public class CustomerBillOnDemandApiControllerTest { + + private final TMForumMapper tmForumMapper = new TMForumMapperImpl(); + private final CustomerBillOnDemandRepository customerBillOnDemandRepository = + mock(CustomerBillOnDemandRepository.class); + private final ReferencesRepository referencesRepository = mock(ReferencesRepository.class); + private final ReferenceValidationService validationService = + new ReferenceValidationService(referencesRepository); + private CustomerBillOnDemandApiController customerBillOnDemandApiController; + + @BeforeEach + public void setup() { + customerBillOnDemandApiController = + new CustomerBillOnDemandApiController(tmForumMapper, + customerBillOnDemandRepository, validationService); + } + + private CustomerBillOnDemandVO getCustomerBill(CustomerBillOnDemandVO customerBill) { + return customerBill; + } + + @DisplayName("CustomerBillOnDemand created") + @Test + void testCreateCustomerBillOnDemand() { + CustomerBillOnDemandCreateVO customerCreateVO = new CustomerBillOnDemandCreateVO(); + customerCreateVO.setName("Customer bill on demand Name"); + CustomerBillOnDemandVO customerMockVO = tmForumMapper.map(customerCreateVO); + + RelatedPartyRefVO relatedPartyVO = new RelatedPartyRefVO(); + relatedPartyVO.setName("Related party ref name"); + relatedPartyVO.setRole("Related party ref role"); + relatedPartyVO.setId("id1"); + customerCreateVO.setRelatedParty(relatedPartyVO); + + // Stub customer repo create + when(customerBillOnDemandRepository.createCustomerBillOnDemand(anyObject())) + .thenReturn(Completable.fromAction(() -> getCustomerBill(customerMockVO))); + + // Stub references repo ref exists + when(referencesRepository.referenceExists(anyString(), anyList())) + .thenReturn(Maybe.just(relatedPartyVO)); + + Single> singleResponse = + customerBillOnDemandApiController.createCustomerBillOnDemand(customerCreateVO); + CustomerBillOnDemandVO customerResponseVO = singleResponse.blockingGet().body(); + + assertEquals(HttpStatus.CREATED, + singleResponse.blockingGet().getStatus(), + "A customer bill on demand response with status CREATED is expected."); + assertTrue(singleResponse.blockingGet().getBody().isPresent(), + "A customer bill on demand response contains object"); + assertEquals(customerCreateVO.getName(), + customerResponseVO.getName(), + "Returned customer bill on demand should have equal name compared to the created one"); + } + + @DisplayName("CustomerBillOnDemand received") + @Test + void testReceiveCustomerBillOnDemand() { + CustomerBillOnDemandVO customerBillVO = new CustomerBillOnDemandVO(); + customerBillVO.setName("Customer bill on demand name"); + customerBillVO.setId("id1"); + CustomerBillOnDemand customerBill = tmForumMapper.map(customerBillVO); + + // Stub customer bill repo receive + when(customerBillOnDemandRepository.getCustomerBillOnDemand("id1")) + .thenReturn(Maybe.just(customerBill)); + + // Retrieve customer + HttpResponse customerBillVOHttpResponse = + customerBillOnDemandApiController.retrieveCustomerBillOnDemand("id1", null).blockingGet(); + assertEquals(HttpStatus.OK, + customerBillVOHttpResponse.getStatus(), + "A customer bill on demand response has OK status"); + assertTrue(customerBillVOHttpResponse.getBody().isPresent(), "A customer bill response has object body."); + assertEquals(customerBillVO, + customerBillVOHttpResponse.getBody().get(), + "The same customer bill on demand was returned"); + + } +} diff --git a/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java b/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java index a585b05b..7de5be58 100644 --- a/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java +++ b/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java @@ -30,8 +30,9 @@ * Unit Tests for CustomerApiController * * TODO: - * * Tests for listCustomer - * * Tests for delete + * - Tests for listCustomer + * - Tests for delete + * - Tests for patch */ public class CustomerApiControllerTest { From 6705949eb4f3664260a6e0d5188cbcd03c5c2c1b Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Thu, 6 Oct 2022 14:00:35 +0200 Subject: [PATCH 15/16] * Adapt customer API to reactor * Started adapting customer API tests --- customer-bill/pom.xml | 24 ++- customer/pom.xml | 24 ++- .../tmforum/customer/TMForumMapper.java | 11 +- .../exception/CustomerCreationException.java | 11 +- .../exception/CustomerDeletionException.java | 19 ++ .../exception/CustomerExceptionReason.java | 9 + .../exception/CustomerListException.java | 12 ++ .../exception/CustomerUpdateException.java | 20 ++ .../repository/CustomerRepository.java | 59 ++++-- .../customer/rest/CustomerApiController.java | 113 ++++++++--- .../tmforum/customer/CustomerApiIT.java | 190 ++++++------------ .../rest/CustomerApiControllerTest.java | 25 ++- 12 files changed, 302 insertions(+), 215 deletions(-) create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerDeletionException.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerExceptionReason.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerListException.java create mode 100644 customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerUpdateException.java diff --git a/customer-bill/pom.xml b/customer-bill/pom.xml index a4606c71..43fbc82a 100644 --- a/customer-bill/pom.xml +++ b/customer-bill/pom.xml @@ -12,6 +12,14 @@ 0.1 + + https://tmf-open-api-table-documents.s3.eu-west-1.amazonaws.com/OpenApiTable/4.0.0/swagger/TMF678-CustomerBill-v4.0.0.swagger.json + https://tmf-open-api-table-documents.s3.eu-west-1.amazonaws.com/OpenApiTable/4.0.0/ctk/TMF678-Customer_Bill_V4-0-0.zip + TMF678_Customer_Bill_V4-0-0 + Mac-Linux-RUNCTK.sh + /tmf-api/customerBillManagement/v4/ + + org.fiware.tmforum @@ -78,13 +86,13 @@ compile - io.micronaut.rxjava2 - micronaut-rxjava2 + io.micronaut + micronaut-jackson-core compile - io.micronaut - micronaut-jackson-core + io.micronaut.reactor + micronaut-reactor compile @@ -183,16 +191,14 @@ generate - ${project.parent.basedir}/api/customer-bill.yaml + ${tmforum.api.url} org.fiware.customer_bill.api true org.fiware.customer_bill.model - true micronaut - false - false VO ${project.build.directory} + false true false @@ -202,7 +208,7 @@ false true false - true + true java.util.Date=java.time.Instant diff --git a/customer/pom.xml b/customer/pom.xml index 0c7feb87..2eed186d 100644 --- a/customer/pom.xml +++ b/customer/pom.xml @@ -12,6 +12,14 @@ 0.1 + + https://tmf-open-api-table-documents.s3.eu-west-1.amazonaws.com/OpenApiTable/4.0.0/swagger/TMF629-Customer-v4.0.0.swagger.json + https://tmf-open-api-table-documents.s3.eu-west-1.amazonaws.com/OpenApiTable/4.0.0/ctk/TMF629-Customer-v4.0.0.zip + TMF629-Customer-v4.0.0 + Mac-Linux-RUNCTK.sh + /tmf-api/customerManagement/v4 + + org.fiware.tmforum @@ -78,13 +86,13 @@ compile - io.micronaut.rxjava2 - micronaut-rxjava2 + io.micronaut + micronaut-jackson-core compile - io.micronaut - micronaut-jackson-core + io.micronaut.reactor + micronaut-reactor compile @@ -183,16 +191,14 @@ generate - ${project.parent.basedir}/api/customer.yaml + ${tmforum.api.url} org.fiware.customer.api true org.fiware.customer.model - true micronaut - false - false VO ${project.build.directory} + false true false @@ -202,7 +208,7 @@ false true false - true + true java.util.Date=java.time.Instant diff --git a/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java b/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java index c1784d46..3e9ded2b 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/TMForumMapper.java @@ -21,12 +21,17 @@ public interface TMForumMapper { // using inline expression, since else it might overwrite the String-String mapping - @Mapping(target = "id", expression = "java(java.lang.String.format(ID_TEMPLATE, \"customer\", java.util.UUID.randomUUID()))") - @Mapping(target = "href", ignore = true) - CustomerVO map(CustomerCreateVO customerCreateVO); + @Mapping(target = "id", source = "id") + @Mapping(target = "href", source = "id") + CustomerVO map(CustomerCreateVO customerCreateVO, URI id); + + @Mapping(target = "id", source = "id") + @Mapping(target = "href", source = "id") + CustomerVO map(CustomerUpdateVO customerUpdateVO, String id); CustomerVO map(Customer customer); + @Mapping(target = "href", source = "id") Customer map(CustomerVO customerVO); RelatedParty map(RelatedPartyVO relatedPartyVO); diff --git a/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerCreationException.java b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerCreationException.java index 11c6f82d..635c394c 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerCreationException.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerCreationException.java @@ -1,15 +1,22 @@ package org.fiware.tmforum.customer.exception; +import lombok.Getter; + /** * Exception to be thrown in case a customer could not have been created. */ public class CustomerCreationException extends RuntimeException { - public CustomerCreationException(String message) { + @Getter + private final CustomerExceptionReason customerExceptionReason; + + public CustomerCreationException(String message, CustomerExceptionReason customerExceptionReason) { super(message); + this.customerExceptionReason = customerExceptionReason; } - public CustomerCreationException(String message, Throwable cause) { + public CustomerCreationException(String message, Throwable cause, CustomerExceptionReason customerExceptionReason) { super(message, cause); + this.customerExceptionReason = customerExceptionReason; } } diff --git a/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerDeletionException.java b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerDeletionException.java new file mode 100644 index 00000000..8613c246 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerDeletionException.java @@ -0,0 +1,19 @@ +package org.fiware.tmforum.customer.exception; + +import lombok.Getter; + +public class CustomerDeletionException extends RuntimeException { + + @Getter + private final CustomerExceptionReason customerExceptionReason; + + public CustomerDeletionException(String message, CustomerExceptionReason customerExceptionReason) { + super(message); + this.customerExceptionReason = customerExceptionReason; + } + + public CustomerDeletionException(String message, Throwable cause, CustomerExceptionReason customerExceptionReason) { + super(message, cause); + this.customerExceptionReason = customerExceptionReason; + } +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerExceptionReason.java b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerExceptionReason.java new file mode 100644 index 00000000..b0253d20 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerExceptionReason.java @@ -0,0 +1,9 @@ +package org.fiware.tmforum.customer.exception; + +public enum CustomerExceptionReason { + CONFLICT, + INVALID_DATA, + INVALID_RELATIONSHIP, + NOT_FOUND, + UNKNOWN; +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerListException.java b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerListException.java new file mode 100644 index 00000000..ffc8a044 --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerListException.java @@ -0,0 +1,12 @@ +package org.fiware.tmforum.customer.exception; + +public class CustomerListException extends RuntimeException { + + public CustomerListException(String message) { + super(message); + } + + public CustomerListException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerUpdateException.java b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerUpdateException.java new file mode 100644 index 00000000..9951daba --- /dev/null +++ b/customer/src/main/java/org/fiware/tmforum/customer/exception/CustomerUpdateException.java @@ -0,0 +1,20 @@ +package org.fiware.tmforum.customer.exception; + +import lombok.Getter; + +public class CustomerUpdateException extends RuntimeException { + + @Getter + private final CustomerExceptionReason customerExceptionReason; + + public CustomerUpdateException(String message, CustomerExceptionReason customerExceptionReason) { + super(message); + this.customerExceptionReason = customerExceptionReason; + } + + public CustomerUpdateException(String message, Throwable cause, CustomerExceptionReason customerExceptionReason) { + super(message, cause); + this.customerExceptionReason = customerExceptionReason; + } + +} diff --git a/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java b/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java index 53afc465..e78ca9af 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/repository/CustomerRepository.java @@ -1,15 +1,19 @@ package org.fiware.tmforum.customer.repository; -import io.reactivex.Completable; -import io.reactivex.Maybe; -import io.reactivex.Single; -import org.fiware.ngsi.api.EntitiesApi; +import io.micronaut.http.HttpStatus; +import io.micronaut.http.client.exceptions.HttpClientResponseException; +import org.fiware.ngsi.api.EntitiesApiClient; import org.fiware.ngsi.model.EntityVO; import org.fiware.tmforum.common.configuration.GeneralProperties; +import org.fiware.tmforum.common.mapping.NGSIMapper; import org.fiware.tmforum.common.repository.NgsiLdBaseRepository; import org.fiware.tmforum.customer.domain.customer.Customer; +import org.fiware.tmforum.customer.exception.CustomerDeletionException; +import org.fiware.tmforum.customer.exception.CustomerExceptionReason; +import org.fiware.tmforum.customer.exception.CustomerListException; import org.fiware.tmforum.mapping.EntityVOMapper; import org.fiware.tmforum.mapping.JavaObjectMapper; +import reactor.core.publisher.Mono; import javax.inject.Singleton; import java.net.URI; @@ -21,29 +25,38 @@ public class CustomerRepository extends NgsiLdBaseRepository { private final EntityVOMapper entityVOMapper; + private final NGSIMapper ngsiMapper; private final JavaObjectMapper javaObjectMapper; - public CustomerRepository(GeneralProperties generalProperties, EntitiesApi entitiesApi, EntityVOMapper entityVOMapper, JavaObjectMapper javaObjectMapper) { + public CustomerRepository(GeneralProperties generalProperties, EntitiesApiClient entitiesApi, EntityVOMapper entityVOMapper, NGSIMapper ngsiMapper, JavaObjectMapper javaObjectMapper) { super(generalProperties, entitiesApi); this.entityVOMapper = entityVOMapper; + this.ngsiMapper = ngsiMapper; this.javaObjectMapper = javaObjectMapper; } - public Completable createCustomer(Customer customer) { + public Mono createCustomer(Customer customer) { return createEntity(javaObjectMapper.toEntityVO(customer), generalProperties.getTenant()); } - public Completable deleteCustomer(String id) { - return entitiesApi.removeEntityById(URI.create(id), generalProperties.getTenant(), null); + public Mono deleteCustomer(URI id) { + return entitiesApi.removeEntityById(id, generalProperties.getTenant(), null) + .onErrorResume(t -> { + if (t instanceof HttpClientResponseException e && e.getStatus().equals(HttpStatus.NOT_FOUND)) { + throw new CustomerDeletionException(String.format("Was not able to delete %s, since it does not exist.", id), + CustomerExceptionReason.NOT_FOUND); + } + throw new CustomerDeletionException(String.format("Was not able to delete %s.", id), + t, + CustomerExceptionReason.UNKNOWN); + }); } - public Single> findCustomers() { + public Mono> findCustomers(Integer offset, Integer limit) { return entitiesApi.queryEntities(generalProperties.getTenant(), - null, - null, - Customer.TYPE_CUSTOMER, null, null, + Customer.TYPE_CUSTOMER, null, null, null, @@ -51,18 +64,28 @@ public Single> findCustomers() { null, null, null, + limit, + offset, + null, getLinkHeader()) .map(List::stream) - .flatMap(entityVOStream -> zipToList(entityVOStream, Customer.class)); + .flatMap(entityVOStream -> zipToList(entityVOStream, Customer.class)) + .onErrorResume(t -> { + throw new CustomerListException("Was not able to list customers.", t); + }); + } + + public Mono updateCustomer(String id, T customer) { + return patchEntity(URI.create(id), ngsiMapper.map(javaObjectMapper.toEntityVO(customer))); } - public Maybe getCustomer(String id) { - return retrieveEntityById(URI.create(id)) - .flatMap(entityVO -> entityVOMapper.fromEntityVO(entityVO, Customer.class).toMaybe()); + public Mono getCustomer(URI id) { + return retrieveEntityById(id) + .flatMap(entityVO -> entityVOMapper.fromEntityVO(entityVO, Customer.class)); } - private Single> zipToList(Stream entityVOStream, Class targetClass) { - return Single.zip( + private Mono> zipToList(Stream entityVOStream, Class targetClass) { + return Mono.zip( entityVOStream.map(entityVO -> entityVOMapper.fromEntityVO(entityVO, targetClass)).toList(), oList -> Arrays.stream(oList).map(targetClass::cast).toList() ); diff --git a/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java b/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java index dab24606..0561887a 100644 --- a/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java +++ b/customer/src/main/java/org/fiware/tmforum/customer/rest/CustomerApiController.java @@ -2,6 +2,7 @@ import io.micronaut.http.HttpResponse; import io.micronaut.http.annotation.Controller; +import io.micronaut.http.client.exceptions.HttpClientResponseException; import io.reactivex.Single; import io.reactivex.schedulers.Schedulers; import lombok.RequiredArgsConstructor; @@ -11,17 +12,28 @@ import org.fiware.customer.model.CustomerUpdateVO; import org.fiware.customer.model.CustomerVO; import org.fiware.tmforum.common.exception.NonExistentReferenceException; +import org.fiware.tmforum.common.mapping.IdHelper; import org.fiware.tmforum.common.validation.ReferenceValidationService; import org.fiware.tmforum.customer.TMForumMapper; import org.fiware.tmforum.customer.domain.customer.Customer; import org.fiware.tmforum.customer.exception.CustomerCreationException; +import org.fiware.tmforum.customer.exception.CustomerDeletionException; +import org.fiware.tmforum.customer.exception.CustomerExceptionReason; +import org.fiware.tmforum.customer.exception.CustomerUpdateException; import org.fiware.tmforum.customer.repository.CustomerRepository; +import reactor.core.publisher.Mono; import javax.annotation.Nullable; +import java.net.URI; import java.util.List; +import java.util.Optional; +import java.util.UUID; + +import static org.fiware.tmforum.common.CommonConstants.DEFAULT_LIMIT; +import static org.fiware.tmforum.common.CommonConstants.DEFAULT_OFFSET; @Slf4j -@Controller +@Controller("${general.basepath:/}") @RequiredArgsConstructor public class CustomerApiController implements CustomerApi { @@ -30,12 +42,12 @@ public class CustomerApiController implements CustomerApi { private final ReferenceValidationService validationService; @Override - public Single> createCustomer(CustomerCreateVO customerCreateVO) { - CustomerVO customerVO = tmForumMapper.map(customerCreateVO); + public Mono> createCustomer(CustomerCreateVO customerCreateVO) { + CustomerVO customerVO = tmForumMapper.map(customerCreateVO, IdHelper.toNgsiLd(UUID.randomUUID().toString(), Customer.TYPE_CUSTOMER)); Customer customer = tmForumMapper.map(customerVO); - Single customerSingle = Single.just(customer); - Single checkingSingle; + Mono customerMono = Mono.just(customer); + Mono checkingMono; /** * Validate references @@ -49,54 +61,89 @@ public Single> createCustomer(CustomerCreateVO customer * TODO: Check if relatedParty and engagedParty object is correct * - what are allowed ref types? */ - try { - if (customer.getRelatedParty() != null && !customer.getRelatedParty().isEmpty()) { - checkingSingle = validationService.getCheckingSingleOrThrow(customer.getRelatedParty(), customer); - customerSingle = Single.zip(customerSingle, checkingSingle, (p1, p2) -> p1); - } - if (customer.getEngagedParty() != null) { - checkingSingle = - validationService.getCheckingSingleOrThrow( - List.of(customer.getEngagedParty()), - customer); - customerSingle = Single.zip(customerSingle, checkingSingle, (p1, p2) -> p1); - } - } catch (NonExistentReferenceException e) { - throw new CustomerCreationException(String.format("Was not able to create customer %s", customer.getId()), e); + if (customer.getRelatedParty() != null && !customer.getRelatedParty().isEmpty()) { + checkingMono = validationService.getCheckingMono(customer.getRelatedParty(), customer) + .onErrorMap(throwable -> new CustomerCreationException(String.format("Was not able to create customer %s", customer.getId()), throwable, CustomerExceptionReason.INVALID_RELATIONSHIP)); + customerMono = Mono.zip(customerMono, checkingMono, (p1, p2) -> p1); + } + if (customer.getEngagedParty() != null) { + checkingMono = + validationService.getCheckingMono( + List.of(customer.getEngagedParty()), + customer) + .onErrorMap(throwable -> new CustomerCreationException(String.format("Was not able to create customer %s", customer.getId()), throwable, CustomerExceptionReason.INVALID_RELATIONSHIP)); + customerMono = Mono.zip(customerMono, checkingMono, (p1, p2) -> p1); } - return customerSingle - .flatMap(customerToCreate -> customerRepository.createCustomer(customerToCreate).toSingleDefault(customerToCreate)) + return customerMono + .flatMap(customerToCreate -> customerRepository.createCustomer(customerToCreate).then(Mono.just(customerToCreate))) + .onErrorMap(t -> { + if (t instanceof HttpClientResponseException e) { + return switch (e.getStatus()) { + case CONFLICT -> + new CustomerCreationException(String.format("Conflict on creating the customer: %s", e.getMessage()), CustomerExceptionReason.CONFLICT); + case BAD_REQUEST -> + new CustomerCreationException(String.format("Did not receive a valid customer: %s.", e.getMessage()), CustomerExceptionReason.INVALID_DATA); + default -> + new CustomerCreationException(String.format("Unspecified downstream error: %s", e.getMessage()), CustomerExceptionReason.UNKNOWN); + }; + } else { + return t; + } + }) .cast(Customer.class) .map(tmForumMapper::map) - .subscribeOn(Schedulers.io()) .map(HttpResponse::created); } @Override - public Single> deleteCustomer(String id) { - return customerRepository.deleteCustomer(id).toSingleDefault(HttpResponse.noContent()); + public Mono> deleteCustomer(String id) { + + if (!IdHelper.isNgsiLdId(id)) { + throw new CustomerDeletionException("Did not receive a valid id, such organization cannot exist.", CustomerExceptionReason.NOT_FOUND); + } + + return customerRepository.deleteCustomer(URI.create(id)).then(Mono.just(HttpResponse.noContent())); } @Override - public Single>> listCustomer(@Nullable String fields, @Nullable Integer offset, @Nullable Integer limit) { - return customerRepository.findCustomers() + public Mono>> listCustomer(@Nullable String fields, @Nullable Integer offset, @Nullable Integer limit) { + offset = Optional.ofNullable(offset).orElse(DEFAULT_OFFSET); + limit = Optional.ofNullable(limit).orElse(DEFAULT_LIMIT); + + return customerRepository.findCustomers(offset, limit) .map(List::stream) .map(customerStream -> customerStream.map(tmForumMapper::map).toList()) .map(HttpResponse::ok); } @Override - public Single> patchCustomer(String id, CustomerUpdateVO customer) { - // TODO: implement proper patch - return null; + public Mono> patchCustomer(String id, CustomerUpdateVO customerUpdateVO) { + // non-ngsi-ld ids cannot exist. + if (!IdHelper.isNgsiLdId(id)) { + throw new CustomerUpdateException("Did not receive a valid id, such organization cannot exist.", CustomerExceptionReason.NOT_FOUND); + } + + Customer updatedCustomer = tmForumMapper.map(tmForumMapper.map(customerUpdateVO, id)); + + URI idUri = URI.create(id); + return customerRepository.updateCustomer(id, updatedCustomer) + .then(customerRepository.getCustomer(idUri)) + .map(tmForumMapper::map) + .map(HttpResponse::ok); } @Override - public Single> retrieveCustomer(String id, @Nullable String fields) { - return customerRepository.getCustomer(id) + public Mono> retrieveCustomer(String id, @Nullable String fields) { + + if (!IdHelper.isNgsiLdId(id)) { + return Mono.just(HttpResponse.notFound()); + } + + return customerRepository.getCustomer(URI.create(id)) .map(tmForumMapper::map) - .toSingle() - .map(HttpResponse::ok); + .map(HttpResponse::ok) + .switchIfEmpty(Mono.just(HttpResponse.notFound())) + .map(HttpResponse.class::cast); } } diff --git a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java index a2282451..c5a1031b 100644 --- a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java +++ b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java @@ -4,16 +4,25 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.micronaut.http.HttpResponse; import io.micronaut.http.HttpStatus; +import io.micronaut.http.client.exceptions.HttpClientResponseException; import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import lombok.RequiredArgsConstructor; import org.fiware.customer.model.*; import org.fiware.tmforum.customer.rest.CustomerApiController; +import org.fiware.tmforum.customer.rest.CustomerApiControllerTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + import java.text.ParseException; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Callable; +import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -28,143 +37,62 @@ */ @RequiredArgsConstructor @MicronautTest(packages = {"org.fiware.tmforum.customer"}) -class CustomerApiIT { - - private final ObjectMapper objectMapper; - private final CustomerApiController customerApiController; - - @Test - void test() throws JsonProcessingException, ParseException { - CustomerCreateVO myFancyFirstCustomerCreate = getMyFancyCustomer( - "My Fancy first Customer", null - ); - - // Test create - HttpResponse myFancyCustomerCreateResponse = - customerApiController.createCustomer(myFancyFirstCustomerCreate).blockingGet(); - assertEquals(HttpStatus.CREATED, - myFancyCustomerCreateResponse.getStatus(), - "Customer should have been created"); - CustomerVO myFancyFirstCustomer = myFancyCustomerCreateResponse.body(); - - // Test create 2nd customer with related party - RelatedPartyVO relatedPartyVO = new RelatedPartyVO(); - relatedPartyVO.setId(myFancyFirstCustomer.getId()); - relatedPartyVO.setRole("My fancy related party role"); - relatedPartyVO.setName("My fancy related party"); - CustomerCreateVO myFancySecondCustomerCreate = getMyFancyCustomer( - "My fancy 2nd customer", - relatedPartyVO - ); - HttpResponse myFancySecondCustomerCreateResponse = - customerApiController.createCustomer(myFancySecondCustomerCreate).blockingGet(); - assertEquals(HttpStatus.CREATED, - myFancySecondCustomerCreateResponse.getStatus(), - "2nd Customer should have been created"); - CustomerVO myFancySecondCustomer = myFancySecondCustomerCreateResponse.body(); - - // Test retrieve of 2nd customer - HttpResponse customerVOHttpResponse = - customerApiController.retrieveCustomer(myFancySecondCustomer.getId(), null).blockingGet(); - assertEquals(HttpStatus.OK, - customerVOHttpResponse.getStatus(), - "A customer response is expected."); - assertTrue(customerVOHttpResponse.getBody().isPresent(), "A customer response is expected."); - assertEquals(myFancySecondCustomer, - customerVOHttpResponse.getBody().get(), - "The full 2nd customer should be retrieved"); - - // TODO: implement test for patch - - // TODO: implement test for listCustomer - - // Test delete 2nd customer - HttpResponse customerDeleteResponse = - customerApiController.deleteCustomer(myFancySecondCustomer.getId()).blockingGet(); - assertEquals(HttpStatus.NO_CONTENT, - customerDeleteResponse.getStatus(), - "A NO_CONTENT response is expected"); - +class CustomerApiIT implements CustomerApiTestSpec { + + private final CustomerApiTestClient customerApiTestClient; + + private CustomerCreateVO customerCreateVO; + private CustomerUpdateVO customerUpdateVO; + private CustomerVO expectedCustomer; + private String message; + + @ParameterizedTest + @MethodSource("provideValidCustomers") + public void createCustomer201(String message, CustomerCreateVO customerCreateVO, CustomerVO expectedCustomer) throws Exception { + this.customerCreateVO = customerCreateVO; + this.expectedCustomer = expectedCustomer; + this.message = message; + createCustomer201(); } - private CustomerCreateVO getMyFancyCustomer(String name, RelatedPartyVO relatedPartyVO) throws JsonProcessingException { - - CustomerCreateVO customerVO = new CustomerCreateVO(); - customerVO.setName(name); - customerVO.setStatus("My fancy status"); - customerVO.setStatusReason("Fancy reason for my fancy status"); - - MediumCharacteristicVO mediumCharacteristicVO = new MediumCharacteristicVO(); - mediumCharacteristicVO.setCity("Berlin"); - mediumCharacteristicVO.setContactType("postal address"); - mediumCharacteristicVO.setCountry("Germany"); - mediumCharacteristicVO.setEmailAddress("my-fancy@company.org"); - mediumCharacteristicVO.setPhoneNumber("0123/4567890-0"); - mediumCharacteristicVO.setFaxNumber("0123/4567890-1"); - mediumCharacteristicVO.setPostCode("10719"); - mediumCharacteristicVO.setSocialNetworkId("@fancy"); - mediumCharacteristicVO.setStateOrProvince("Berlin"); - mediumCharacteristicVO.street1("Kurfürstendamm 12"); - - ContactMediumVO contactMediumVO = new ContactMediumVO(); - contactMediumVO.setMediumType("postal address"); - contactMediumVO.setPreferred(true); - contactMediumVO.setCharacteristic(mediumCharacteristicVO); - contactMediumVO.setValidFor( - new TimePeriodVO() - .startDateTime(Instant.now()) - .endDateTime(Instant.now() - .plus(Duration.of(10, ChronoUnit.DAYS)))); - - AccountRefVO accountRefVO = new AccountRefVO(); - accountRefVO.setId("urn:ngsi-ld:AccountRef:MyAccountRef001"); - accountRefVO.setName("My AccountRef name"); - accountRefVO.setDescription("My AccountRef description"); - - AgreementRefVO agreementRefVO = new AgreementRefVO(); - agreementRefVO.setId("urn:ngsi-ld:AgreementRef:MyAgreementRef001"); - agreementRefVO.setName("My AgreementRef name"); - - CharacteristicVO characteristicVO = new CharacteristicVO(); - characteristicVO.setName("My customer characteristic name"); - characteristicVO.setValue("My customer characteristic value"); - characteristicVO.setValueType("String"); - - CreditProfileVO creditProfileVO = new CreditProfileVO(); - creditProfileVO.setCreditScore(6); - creditProfileVO.setCreditRiskRating(4); - creditProfileVO.setCreditProfileDate(Instant.now()); - - PaymentMethodRefVO paymentMethodRefVO = new PaymentMethodRefVO(); - paymentMethodRefVO.setId("urn:ngsi-ld:PaymentMethodRef:MyPaymentMethodRef001"); - paymentMethodRefVO.setName("My PaymentMethodRef name"); - - if (relatedPartyVO != null) { - customerVO.setRelatedParty(List.of(relatedPartyVO)); - customerVO.setEngagedParty(relatedPartyVO); - } + @Override + public void createCustomer201() throws Exception { + + HttpResponse customerCreateResponse = + callAndCatch(() -> customerApiTestClient.createCustomer(customerCreateVO)); + assertEquals(HttpStatus.CREATED, customerCreateResponse.getStatus(), message); + + CustomerVO createdCustomerVO = customerCreateResponse.body(); + expectedCustomer.setId(createdCustomerVO.getId()); + expectedCustomer.setHref(createdCustomerVO.getId()); + assertEquals(expectedCustomer, createdCustomerVO, message); - customerVO.setContactMedium(List.of(contactMediumVO)); - customerVO.setAccount(List.of(accountRefVO)); - customerVO.setAgreement(List.of(agreementRefVO)); - customerVO.setCharacteristic(List.of(characteristicVO)); - customerVO.setCreditProfile(List.of(creditProfileVO)); - customerVO.setPaymentMethod(List.of(paymentMethodRefVO)); - customerVO.setValidFor( - new TimePeriodVO().startDateTime(Instant.now()) - .endDateTime(Instant.now() - .plus(Duration.of(10, ChronoUnit.DAYS)))); - - return customerVO; } - class TestCharacteristic { - public final long valuation; - public final String unit; + private static Stream provideValidCustomers() { + List validCustomers = new ArrayList<>(); + + CustomerCreateVO customerCreateVO = CustomerCreateVOTestExample.build(); + customerCreateVO.setEngagedParty(null); + customerCreateVO.setRelatedParty(null); + CustomerVO expectedCustomer = CustomerVOTestExample.build(); + expectedCustomer.setEngagedParty(null); + expectedCustomer.setRelatedParty(null); + validCustomers.add( + Arguments.of("Empty customer should have been created.", + customerCreateVO, expectedCustomer)); + + + + return validCustomers.stream(); + } - TestCharacteristic(long valuation, String unit) { - this.valuation = valuation; - this.unit = unit; + // Helper method to catch potential http exceptions and return the status code. + public HttpResponse callAndCatch(Callable> request) throws Exception { + try { + return request.call(); + } catch (HttpClientResponseException e) { + return (HttpResponse) e.getResponse(); } } diff --git a/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java b/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java index 7de5be58..be6ce2ee 100644 --- a/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java +++ b/customer/src/test/java/org/fiware/tmforum/customer/rest/CustomerApiControllerTest.java @@ -6,6 +6,7 @@ import io.reactivex.Maybe; import io.reactivex.Single; import org.fiware.customer.model.*; +import org.fiware.tmforum.common.mapping.IdHelper; import org.fiware.tmforum.common.repository.ReferencesRepository; import org.fiware.tmforum.common.validation.ReferenceValidationService; import org.fiware.tmforum.customer.TMForumMapper; @@ -17,8 +18,11 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; +import java.net.URI; import java.util.List; +import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -56,7 +60,7 @@ private CustomerVO getCustomer(CustomerVO customer) { void testCreateCustomer() { CustomerCreateVO customerCreateVO = new CustomerCreateVO(); customerCreateVO.setName("Customer Name"); - CustomerVO customerMockVO = tmForumMapper.map(customerCreateVO); + CustomerVO customerMockVO = tmForumMapper.map(customerCreateVO, IdHelper.toNgsiLd(UUID.randomUUID().toString(), Customer.TYPE_CUSTOMER)); RelatedPartyVO relatedPartyVO = new RelatedPartyVO(); relatedPartyVO.setName("Related party name"); @@ -67,20 +71,21 @@ void testCreateCustomer() { // Stub customer repo create when(customerRepository.createCustomer(anyObject())) - .thenReturn(Completable.fromAction(() -> getCustomer(customerMockVO))); + .thenReturn(Mono.empty()); + //.thenReturn(Completable.fromAction(() -> getCustomer(customerMockVO))); // Stub references repo ref exists when(referencesRepository.referenceExists(anyString(), anyList())) - .thenReturn(Maybe.just(relatedPartyVO)); + .thenReturn(Mono.just(relatedPartyVO)); - Single> singleResponse = + Mono> monoResponse = customerApiController.createCustomer(customerCreateVO); - CustomerVO customerResponseVO = singleResponse.blockingGet().body(); + CustomerVO customerResponseVO = monoResponse.block().body(); assertEquals(HttpStatus.CREATED, - singleResponse.blockingGet().getStatus(), + monoResponse.block().getStatus(), "A customer response with status CREATED is expected."); - assertTrue(singleResponse.blockingGet().getBody().isPresent(), + assertTrue(monoResponse.block().getBody().isPresent(), "A customer response contains object"); assertEquals(customerCreateVO.getName(), customerResponseVO.getName(), @@ -96,12 +101,12 @@ void testReceiveCustomer() { Customer customer = tmForumMapper.map(customerVO); // Stub customer repo receive - when(customerRepository.getCustomer("id1")) - .thenReturn(Maybe.just(customer)); + when(customerRepository.getCustomer(URI.create("id1"))) + .thenReturn(Mono.just(customer)); // Retrieve customer HttpResponse customerVOHttpResponse = - customerApiController.retrieveCustomer("id1", null).blockingGet(); + customerApiController.retrieveCustomer("id1", null).block(); assertEquals(HttpStatus.OK, customerVOHttpResponse.getStatus(), "A customer response has OK status"); From fbb24f3d3b8b9d3fafd5b9427d042514ad2a8cf2 Mon Sep 17 00:00:00 2001 From: Dennis Wendland Date: Wed, 26 Oct 2022 14:44:16 +0200 Subject: [PATCH 16/16] Add empty tests --- .../tmforum/customer/CustomerApiIT.java | 192 ++++++++++++++++++ 1 file changed, 192 insertions(+) diff --git a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java index c5a1031b..e849c525 100644 --- a/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java +++ b/customer/src/test/java/org/fiware/tmforum/customer/CustomerApiIT.java @@ -7,6 +7,8 @@ import io.micronaut.http.client.exceptions.HttpClientResponseException; import io.micronaut.test.extensions.junit5.annotation.MicronautTest; import lombok.RequiredArgsConstructor; +import org.fiware.customer.api.CustomerApiTestClient; +import org.fiware.customer.api.CustomerApiTestSpec; import org.fiware.customer.model.*; import org.fiware.tmforum.customer.rest.CustomerApiController; import org.fiware.tmforum.customer.rest.CustomerApiControllerTest; @@ -69,6 +71,196 @@ public void createCustomer201() throws Exception { } + @Override + public void createCustomer400() throws Exception { + + } + + @Override + public void createCustomer401() throws Exception { + + } + + @Override + public void createCustomer403() throws Exception { + + } + + @Override + public void createCustomer405() throws Exception { + + } + + @Override + public void createCustomer409() throws Exception { + + } + + @Override + public void createCustomer500() throws Exception { + + } + + @Override + public void deleteCustomer204() throws Exception { + + } + + @Override + public void deleteCustomer400() throws Exception { + + } + + @Override + public void deleteCustomer401() throws Exception { + + } + + @Override + public void deleteCustomer403() throws Exception { + + } + + @Override + public void deleteCustomer404() throws Exception { + + } + + @Override + public void deleteCustomer405() throws Exception { + + } + + @Override + public void deleteCustomer409() throws Exception { + + } + + @Override + public void deleteCustomer500() throws Exception { + + } + + @Override + public void listCustomer200() throws Exception { + + } + + @Override + public void listCustomer400() throws Exception { + + } + + @Override + public void listCustomer401() throws Exception { + + } + + @Override + public void listCustomer403() throws Exception { + + } + + @Override + public void listCustomer404() throws Exception { + + } + + @Override + public void listCustomer405() throws Exception { + + } + + @Override + public void listCustomer409() throws Exception { + + } + + @Override + public void listCustomer500() throws Exception { + + } + + @Override + public void patchCustomer200() throws Exception { + + } + + @Override + public void patchCustomer400() throws Exception { + + } + + @Override + public void patchCustomer401() throws Exception { + + } + + @Override + public void patchCustomer403() throws Exception { + + } + + @Override + public void patchCustomer404() throws Exception { + + } + + @Override + public void patchCustomer405() throws Exception { + + } + + @Override + public void patchCustomer409() throws Exception { + + } + + @Override + public void patchCustomer500() throws Exception { + + } + + @Override + public void retrieveCustomer200() throws Exception { + + } + + @Override + public void retrieveCustomer400() throws Exception { + + } + + @Override + public void retrieveCustomer401() throws Exception { + + } + + @Override + public void retrieveCustomer403() throws Exception { + + } + + @Override + public void retrieveCustomer404() throws Exception { + + } + + @Override + public void retrieveCustomer405() throws Exception { + + } + + @Override + public void retrieveCustomer409() throws Exception { + + } + + @Override + public void retrieveCustomer500() throws Exception { + + } + private static Stream provideValidCustomers() { List validCustomers = new ArrayList<>();