Perform sale of articles to a customer.

Data Model

A sale is described by a hierarchical data model defined by the XML Schema posps.xsd . The root element is sale . The data model is created by the server on request by the client when calling a startSale operation . The client then manipulates the model by calling the various operations of the port. The server changes the data model, inserts additional information derived from the data, and sends the updated model back to the client.

The server is in control of the data. The client supplies new data when it calls an operation but must discard the data and accept whatever the server sends back as response as the valid form of the data. This makes it possible for the server to correct data, map it to its own native data format, or ignore unsupported information. It also prevents a divergence in the sale as seen by the client and the server.

Returns whether the server is currently ready to start new sales processes. If the operation returns false , calls to startSale will fail. If true is returned, a sale may be started. The client could use this information to go into an "out-of-order" state while the server is not ready. The server may not be ready, for example, when a server component did not boot completely. Starts a new sale and returns its saleId. Initially, the sale is empty. A server must support multiple concurrent open sales per client. Raised when the server currently cannot start a new sale. Adds a position to the sale with the given saleId.

The position describes the sale of an article with a given quantity. The articleId should be taken from an article search. The position can optionally reference a prescription which prescribes the article. After a position was created, the article cannot be changed.

The server creates a new positionId which is used to refer to the position. The positionId is only valid in the context of the current sale.

The server responds with the updated data model. Usually, it contains a new position element for the added position with a newly generated positionId and an updated total entry.

Raised when a position cannot be added because the sale is in a wrong state. Positions cannot be changed when a payment has already been confirmed and has not been canceled. Raised when the saleId, articleId, or prescriptionId are unknown.
Changes one or more parameters of the given position. The server responds with the updated data model. Usually, the position and the total have been updated. Raised when a position cannot be edited because the sale is in a wrong state. Positions cannot be changed when a payment has already been confirmed and has not been canceled. Raised when the saleId, positionId, or prescriptionId are unknown. Deletes the given position from the sale. The server responds with the updated data model. Usually, the position is removed and the total entry has been updated. Raised when a position cannot be deleted because the sale is in a wrong state. Positions cannot be changed when a payment has already been confirmed and has not been canceled. Raised when the saleId or positionId are unknown. Adds a person to the sale with the given saleId.

The person can either be a person already known to the server and referenced by a personId obtained by a person search or a new person with the data supplied by the client. It is up to the server to decide whether it should create a new entry in the server person store for a person supplied by the client. If it thinks the person data matches an existing entry, it might return the corresponding personId instead of creating a new entry.

The role the person plays in the sale depends on from where it is referenced. It might be the customer if it is referenced by setCustomer , a patient if it is referenced by a prescription, or a physician.

The server responds with the updated data model. Usually, it contains a new person element for the person and possibly an updated total entry. If the person with the personId has already been part of the sale, the existing person entry is updated if the person was changed by the operation.

Raised when the saleId or personId are unknown.
Changes the data of a person previously added to the sale. The server responds with the updated data model. Usually, the person and perhaps the total will have been updated. Raised when a person cannot be edited because the sale is in a wrong state. Persons cannot be changed when a payment has already been confirmed and has not been canceled. Raised when the saleId or personId are unknown or the personId is not part of the sale. Deletes the given Person from the sale. The server responds with the updated data model. Usually, the person is removed and perhaps the total is updated. Raised when the saleId or personId are unknown or the personId is not part of the sale. Raised when the person cannot be deleted because it is referenced from another element of the sale. Adds a prescription to the sale with the given saleId.

A prescription can be referenced by one or more positions meaning that the position is sold as indicated by the prescription. This can change the price the customer has to pay for the position according to local laws.

The prescription can reference to two person elements - to the patient and the physician.

The server responds with the updated data model. Usually, it contains a new prescription element for the new prescription.

Raised when a prescription cannot be edited because the sale is in a wrong state. Prescriptions cannot be changed when a payment has already been confirmed and has not been canceled. Raised when the saleId or personId are unknown or the personId is not part of the sale.
Changes the data of a prescription previously added to the sale. The server responds with the updated data model. Usually, it contains an updated prescription entry for the changed prescription and perhaps updated position entries and an updated total entry. Raised when a prescription cannot be edited because the sale is in a wrong state. Prescriptions cannot be changed when a payment has already been confirmed and has not been canceled. Raised when the saleId, prescriptionId, or personId are unknown or the prescriptionId or personId are not part of the sale. Deletes the given prescription from the sale. The server responds with the updated data model. Usually, the prescription element is removed. Raised when a prescription cannot be edited because the sale is in a wrong state. Prescriptions cannot be changed when a payment has already been confirmed and has not been canceled. Raised when the saleId, prescriptionId, or personId are unknown or the prescriptionId or personId are not part of the sale. Raised when the prescription cannot be deleted because it is referenced to by another element of the sale. Sets the pharmacist who is operating the client and serving the customer.

Setting the operator of a sale is optional since there is no operator in case of a self-service sale. If an operator is already set when the operation is called, the old operator will be overwritten with the new one. To delete the operator from the sale, pass a nil value.

The server responds with the updated data model. Usually, it contains an operator entry for the operator which has been set.

Raised when the saleId is unknown.
Sets the customer who is served by the client.

If there is not already a person element for the customer, the server will add it to the sale. Setting the customer is optional, for a simple sale no customer data is needed. If a customer is already set when the operation is called, the old customer will be overwritten with the new one. To delete the customer from the sale, pass a nil value.

The server responds with the updated data model. Usually, it contains a customer entry for the customer who has been set.

Raised when the customer cannot be set because the sale is in a wrong state. The customer cannot be set when a payment has already been confirmed and has not been canceled. Raised when the saleId or personId are unknown or the personId is not part of the sale.
Asks the server to enable pickup for the given sale.

If pickup is enabled, the client will be allowed to sell articles which it currently cannot deliver. The customer can return later to the pharmacy and pick up the articles which were not delivered. To allow this, createSaleReceipt will usually generate a receipt that contains some pickup information the customer can present to the pharmacist.

If the server allows pickup, it will set the pickup element in the returned data model . If the element is not set, pickup will not be allowed. It is the responsibility of the client to take this into account and to only sell deliverable articles.

The client can try to enable pickup at any time in the sale, as long it is not too late to roll back the transaction if the server does not allow pickup. If pickup is already enabled, the call will be ignored and the server should return an unchanged data model.

Raised when the saleId is unknown.
Asks the server to enable shipment for the given sale.

If shipment is enabled, the client will be allowed to sell articles which it currently cannot deliver. The pharmacist will send the undelivered articles to the person set by the operation. To disable shipment, pass a nil value for the personId.

If the server allows shipment, it will set the shipment element in the returned data model . If the element is not set, shipment will not be allowed. It is the responsibilty of the client to take this into account and to only sell deliverable articles. Shipment may incur shipping charges, in which case a total element including the charges is returned.

Raised when shipment cannot be enabled because the sale is in a wrong state. Shipment cannot be enabled when a payment has already been confirmed and has not been canceled and shipping would change the total. Raised when the saleId or personId are unknown or the personId is not part of the sale.

Adds a charge/rebate to the charges/rebates of this sale. If there already exists a charge of the given kind in the sale, the amount given is added to the existing amount. If no amount is given, the server is expected to add an amount configured on the server side, e. g. it could calculate shipping charges or use a preset night duty charge.

Raised when an uncanceled payment has already been confirmed. Raised when the saleId is unknown.

Deletes the charge of the given type from the sale.

Raised when an uncanceled payment has already been confirmed. Raised when the saleId is unknown.

Notification to the server about the payment process selected by the client for this sale. If the payment is canceled (the canceled parameter is true), the payment has been aborted and the customer has been given back his money. Otherwise (an "uncanceled payment"), the client has collected the total amount which the server has specified for this sale and this transaction cannot be undone any more. The client can confirm an arbitrary number of canceled payments, but once an uncanceled payment has been confirmed, there must be no more payment transactions.

After confirmation of an uncanceled payment the server will reject all changes to the sale that would change the total with a IllegalStateFault . If the receipt is to contain information on the payment type (as it is customary done), the payment must be confirmed before createSaleReceipt is called.

Raised when an uncanceled payment has already been confirmed. Raised when the saleId is unknown.
Notification to the server that client has successfully delivered (dispensed) some or all packs belonging to this sale to the customer. The operation takes as parameters the position(s) and amount of packs which have been delivered. The client must only call this operation after it has ordered the articles via the Order port and the packs have been delivered and handed out to the customer. This operation is usually called only once after payment has been confirmed, but may be called multiple times, perhaps for different positions. Raised if the saleId or a positionId is unknown. Creates a receipt with the data of the given sale. If the sale is still incomplete (payment not confirmed), the server will not return a receipt. The format of the receipt has to be previously agreed upon by server and client. (TODO: receipt format specification) Raised when the saleId is unknown. Closes the sale indicating that the client will not use the sale any further. After a call to closeSale , the saleId must become invalid and calls which use this ID must raise an UnknownIdFault . Raised when the saleId is unknown.
Performs searches for articles and persons in the server database.

Searches are usually performed during a sale to look up articles and persons that are to be included in the search. Alternatively, the client can use a user interface to perform searches independently of a sale.

In order to achieve fast feedback for searches, server and client can control how many elements from the search result are to be returned for each operation invocation. The search... returns the first elements of the result, and the remaining elements (if any) can be fetched by repeatedly calling getNextSearchResults .

The many possibilities for which the search port can be used also means that the server must support several concurrently open searches. The open searches are identified by their searchResultId. A search result is closed if either the client has received all search result elements or it invokes discardSearchResults, or the server discards it after the client has not used the search result ID for a long time. If the server has an internal limit on the number of parallel searches and the limit is reached, it raises a TooManySearchesFault. The client should react by closing other search results before starting a new search.

Searches the article database for articles matching the given pattern.

This is usually the first step when adding an article to a sale. The pharmacist searches for an article, and the articleId of the selected element of the search result is used to add the article to a sale.

If not all elements from the search result are returned, the remaining elements can be requested with getNextSearchResults using the searchResultId returned by this operation.

Searches the person database for persons matching the given pattern. If not all elements from the search result are returned, the remaining elements can be requested with getNextSearchResults using the searchResultId returned by this operation. Returns the next elements from the set of results of a search. Once all results are returned, the client must not use the searchResultId any longer. Raised when the searchId is unknown. Discards any remaining results of a search which have not been fetched yet. The client may not use the searchId any longer after it called this operation. If the operation is called with an unknown searchId or a searchId without remaining elements, it will be ignored.
Order articles for delivery to the POS.

Instead of communicating with the robot directly to fetch sold articles, the posps service leaves it to the pharmacy system to control the article delivery. This enables the pharmacy system to correctly maintain the inventory and to implement advanced features such as reservation of items.

IMPORTANT: If the OrderPort is supported by the server, all other ports must be supported (implemented) too.

Returns whether the server is currently ready to deliver articles ordered by the client. If the operation returns false , calls to orderArticles and orderPickupOrders will always result in delivery errors. If true is returned, orders placed may or may not succeed. The client can use this information to go into an "out-of-order" state while the server is not ready. Requests one or more articles for delivery to the client.

The server will try to deliver the articles to the output location configured for the client. The operation returns immediately, returning an orderId which the client can use to track the status of the order. The orderId may only be valid for the client that placed the order.

A client may place several orders at the same time that the server should handle in FIFO order. A server implementation should try to handle as many concurrent orders as possible, but if for some reason it currently cannot accept more orders, it raises a TooManyOrdersFault.

The server must guarantee that the article delivered for an articleId matches the data (especially product and price) that the server supplies for a sale position with the same articleId. The details which data must match is dependent on the regulations of the country in which the system is used. The PS must also try as far as possible not to deliver an article that has already expired.

Raised when the server does not know at least one of the given articleIds. Raised when the server currently cannot accept any orders. The client should try to place the order later.
Requests a pickup order for delivery to the client.

A pickup order may consist of one or more articles. The server is responsible for assigning the pickupOrderId to the packages that have to be delivered. Either the pharmacist pre-packaged the articles into a single package or the PS orders the articles individually from the pharmacy robot. In both cases, the articles should be listed individually in the result to this call.

The server will try to deliver the pack(s) to the output location configured for the client. The operation returns immediately, returning an orderId that the client can use to track the status of the order. The orderId may only be valid for the client that placed the order.

A client may place several orders at the same time that the server should handle in FIFO order. A server implementation should try to handle as many concurrent orders as possible, but if for some reason it currently cannot accept more orders, it raises a TooManyOrdersFault.

Raised when the server does not know the pickupOrderId. Raised when the server currently cannot accept any orders. The client should try to place the order later.
Returns the status of an order previously placed using orderArticles or orderPickupOrder or of all articles from this sale.

If trackOrder is requested with orderId it returns a list with the current order statuses of the ordered packs.

If trackOrder is requested with saleId it returns a list with the current order statuses of all articles from this sale.

The client will poll until all packs of the order/sale have been processed (either delivered or failed).

The server may discard the orderId after the sale is closed or aborted.

Raised when the server does not know the given orderId or saleId. This may happen because an invalid orderId or saleId was sent or because the order information has already been deleted by the server.
Aborts a running order and cancels all outstanding packs.

The server should try to stop the delivery of all packs that have not already been delivered. This will not always be possible since the server may already have sent an order to the robot. Since some articles may still be in delivery, the order can still be incomplete and has to be tracked to await completion. Packs which were not delivered due to the order being aborted are listed as failed articles with reason code aborted .

A call to abort on an already aborted order is ignored.

Raised when the server does not know the given orderId. This may happen because an invalid orderId was sent or because the order information has already been deleted by the server.
Perform the pickup of articles previously ordered by the customer. The articles are logically put together by the pharmacist into a single package which is picked up as a whole. Physically, the pharmacy robot may still deliver the articles individually.

Data Model

A pickup is described by a hierarchical data model defined by the XML Schema posps.xsd . The root element is pickup . The data model is created by the server on request by the client when calling the operation startPickup . The client then manipulates the model by calling the various operations of the port. The server changes the data model, inserts additional information derived from the data, and sends the updated data model back to the client.

The server is in control of the data. The client supplies new data when calling an operation but must discard the data and accept whatever the server sends back as response as the valid form of the data. This enables the server to correct data, map it to its own native data format, or ignore unsupported information. It also prevents a divergence in the pickup as seen by the client and the server.

Returns whether the server is currently ready to start new pickups. If the operation returns false , calls to startSale will fail. If true is returned, a pickup may be started. The client might use this information to go into an "out-of-order" state while the server is not ready. The server may not be ready, for example, when a server component did not boot completely. Starts a new pickup and returns its pickupId. Initially, the pickup is empty. A server must support multiple concurrent open pickups per client. Raised when the server currently cannot start a new pickup. Sets the pickup code for the pickup with the given pickupId.

Sets the customer-provided code which identifies a pickup order to the server. The customer must have earlier aquired the code by some means not specified by this interface.

The specification does not define how the code is to be generated. To prevent customers from picking up pickup orders that are not meant for them, it should not be easy to guess valid codes. On the other hand, codes should not be too long so that it is not too difficult for the customer to enter it.

Codes not accepted by the server (invalid format, unknown, etc.) are reported by UnknownPickupCodeFault . If the authentication is not accepted, it raises an AuthenticationRejectedFault . If the server accepts a pickup code, it sends back the data model containing the list of articles put together for this pickup, a pickupId with which the client can order the pickup order using the Order port, and possibly customer information with a person element. Once a pickup code is accepted, no further calls to setPickupCode are allowed for this pickup.

Raised when the pickup code cannot be set because a code has already been accepted. Raised when the pickupId is unknown. Raised if there is no pickup with the given pickup id. Raised if the server does not accept the authentication and therefore refuses the given pickup code. This does not imply that there really is a pickup code with the given pickup id.
Sets the pharmacist who is operating the client and serving the customer.

Setting the operator of a pickup is optional since there is no operator in case of a self-service sale. If an operator is already set when the operation is called, the old operator will be overwritten with the new one. To delete the operator from the pickup, pass a nil value.

The server responds with the updated the data model. Usually, it contains an operator entry for the operator which has been set.

Raised when the pickupId or personId are unknown or the personId is not part of the sale.
Notification to the server that the client has successfully collected the total amount from the customer. If the receipt is to contain information on the payment type (as it is customary done), the payment must be confirmed before createPickupReceipt is called. If there are problems handing out the picked-up articles afterwards, the client will give the customer his money back and inform the server by a call to cancelPickupPayment. Raised when payment has already been confirmed and has not been canceled. Raised when the pickupId is unknown. Notification to the server that client has successfully delivered (dispensed) the packs belonging to this pickup order to the customer. The server will set the delivered amount of all positions equal to the total amount. The client must only call this operation after it has ordered the pickup order via the Order port and the packs have been delivered and handed out to the customer. If article delivery has failed for some or all packs, the client must not confirm the delivery, but cancel this pickup order (also cancelling any payment which has already happened). The same has to be done if the ordered packs cannot be dispensed to the customer, e. g. due to a failure in the output tray hardware. Raised if the delivery has already been confirmed. Raised if the pickupId is unknown. Creates a receipt from the data of the given pickup. If the pickup is still incomplete (payment not confirmed), the server will not return a receipt. The format of the receipt has to be previously agreed upon by server and client. Raised when the pickupId is unknown. Closes the pickup, indicating that the client will not use the pickup any further. After a call to closePickup , the pickupId must become invalid and calls which use the ID must raise an UnknownIdFault . Raised when the pickupId is unknown.
Metainformation about the posps server implementation. Clients can query aspects of the server like the implemented posps version and features (profiles) and information about the implementor.

The implementation of PospsPort is required for working with all other ports.

Returns the version number of the posps specification implemented by this posps server. Returns the name of the vendor of this posps server software. Returns information on the software product which implements the posps server. Returns some identification of the "location" where the posps server is installed. This information is meant to help service personnel check that the posps client is talking to the correct server. It is not supposed to be interpreted by the client software itself. For IT systems installed in the pharmacy, this operation might return the pharmacy name and address. Returns the list of profiles or "functionality subsets" supported by this popsps server.
Web service to connect a point of sale (POS) to the pharmacy system (PS). The point of sale acts as the client, which uses the services provided by the pharmacy system server. See overview for a general introduction.

Client identification

If several posps clients are configured to access the same server, the server has to be able to identify the clients. For example, when an article has to be delivered the server has to determine the output location for the articles ordered by a specific client. The specification provides a simple means to identify the calling client by using the posId element. This ID is previously agreed upon between client and server and stored in their configuration (by implementation-specific means which are not covered in this specification).

The posId element is only used as parameter in calls where the server cannot determine the caller ID by other means. For example, it is used in Sale.startSale(), but not in Sale.closeSale(). The server generates a saleId when startSale is called, and it is expected that the server can determine the client by this saleId when it calls closeSale. This keeps the number of arguments passed smaller.

The posId can't be used to securely authenticate the client. If authentication is required between client and server, it should be implemented on the transport level (e. g. by using TLS and certificates) or by using other standards like WS-Security.

Using the posId element in the server is optional. If the server only supports one client, or if the server works the same for all clients, the server can ignore the ID.

Support for different countries and regulations

The posps web service is designed to be adapted for usage in different countries. This does not mean that implementations will have to support all countries that are supported by the specification. It is usually enough if one country is supported.

Country-specific extensions are implemented in several places of the interface. This is done by defining elements that are of the type *CountrySpecific . This type is an abstract base type from which concrete types are derived. A concrete type adds the data that is needed to work in a particular country. The names of the concrete types consist of the name of the base type without the "CountrySpecific" plus a country code which usually consists of two upper-case letters. For example, the type PatientDE , which is a concrete type derived from PatientCountrySpecific , defines elements containing data that has to be processed in a pharmacy system designed for the German market.

An implementation must support the country-specific types of at least one country. There may be cases where additional types are also supported. The implementation might, for example, support several different concrete implementations of AddressCountrySpecific to enable the processing of addresses of customers who live abroad. There is currently no mechanism built into the specification to negotiate which country-specific types are supported by client and server.

At the moment, the specification only defines country-specific types for Germany.

Monetary units

All monetary amounts in elements are given in the smallest unit of the currency of the country in which the sale is carried out. The amount is given without fractions. For example, in Germany prices are given in Euro-Cents, so an amount of 123 means 1.23€.

Operators

The operator is the person who serves and advises the customer at the posps client. Usually this is done by a pharmacist or a pharmacy technician. Since the posps interface is used in circumstances where posps clients are operated by pharmacists who are not usually working for the pharmacy where the client is installed (e. g. service center pharmacists), a mapping from a posps operator to an operator configured the posps server is problematic. The posps interface therefore defines no mechanism to query, create or update operators of the the posps server. It instead assumes that the posps client has its own mechanism for maintaining a database of allowed operators. The operator authenticates with the client and the server is merely informed about this by the client calling setSaleOperator/setPickupOperator .

It should also be noted that it is possible that a customer may be served by several operators consecutively in the same sale/pickup.