Basic selfservice sale example

Overview

This example shows a straightforward selfservice sale carried out by a pharmacy customer using the visavia. The customer uses the customer application touchscreen interface to find the article he wants to buy, pays and collects it. The whole interaction is done without the participation of a pharmacist.

See Examples for an explanation of the elements shown here.

Example

While no sale (or pickup) is in progress, the visavia repeatedly checks if the posps server is available by calling readyForSale.


readyForSale

Request

<sale:readyForSale>
    <posId code="visavia-1"/>
</sale:readyForSale>

Response

<sale:readyForSaleResponse>
    <readyForSale>true</readyForSale>
</sale:readyForSaleResponse>

If the server returns true, the visavia shows a welcome screen to prospective customers. Should the server return false or be not reachable, the visavia goes out of order until a later call succeeds.

welcome screen

When a customer clicks on the touchscreen, he is asked how he wants to proceed.

customer choice

The customer decides to have a look around in the selfservice shop and clicks Enter shop. The visavia begins a new sale process and invokes startSale on the posps server. The server generates an id for the new sale and returns it.


startSale

Request

<sale:startSale>
    <posId code="visavia-1"/>
</sale:startSale>

Response

<sale:startSaleResponse>
    <sale>
        <saleId code="example-1" />
        
        <total>
            <total>0</total>
        </total>
        
    </sale>
</sale:startSaleResponse>

A hierarchical view of articles, the product range, is presented to the customer for easy navigation.

product range

The list of articles underlying this view is maintained by the visavia system itself. Updating the list is not covered by the posps specification. However, the article list only contains hierarchy names and article query information. This information used to fetch the article data from the posps server using the Search port type.

In German visavia installations, PZNs are usually used to identify articles. The visavia therefore uses the PZN search condition of the ArticleConditionDE type to search for the configured PZNs.


searchArticle

Request

      <search:searchArticle>

         <searchpattern>
         
             <!-- the customer can only buy something which is available -->
             <condition>
                 <inStock />
             </condition>
             
            <!-- search by country-specific attribute PZN -->
             <condition>
                 <countrySpecific xsi:type="pptype:ArticleConditionDE">
                     <!-- in real calls, the pzn list may contain hundreds of entries -->
                     <pzn>4479146 8671142 1887991 1275791 1927495 4208045</pzn>
                 </countrySpecific>
             </condition>
         </searchpattern>

         <searchContext>
            <!--  maybe some rebates apply for this sale -->
            <saleId code="example-1"/>
         </searchContext>
         
         <resultTemplate>
            <!-- List all elements the client is interested in. The values
                 are unimportant. The presence alone indicates that the server
                 should fill these elements with the actual values. This can
                 be compared to listing the columns in an SQL SELECT statement. 
              -->
                 
            <!-- In further calls, the visavia will use the articleId
                 instead of the PZN to refer to this articles. -->
            <articleId code="template"/>
            
            <!-- The following information is shown to the customer. -->
            <name />
            <manufacturer />
            <price>0</price>
            <priceContextSpecific>0</priceContextSpecific>
            
            <!-- The customer can choose at most as many articles as are in
                 stock. -->
            <stock>0</stock>
            
            <!-- The packaging is also shown to the customer. -->
            <packaging>
               <description />
            </packaging>
            
            <!-- The visavia needs the PZN to know where to put the
                 resulting article in the tree. -->
            <pharmaceutic>
                <countrySpecific xsi:type="pptype:PharmaceuticArticleDE">
                    <pzn>1234567</pzn>
                </countrySpecific>
            </pharmaceutic>
         </resultTemplate>
         
         <!-- 500 elements at once should not be a problem in local networks -->
         <maxElements>500</maxElements>

         <posId code="visavia-1"/>
      </search:searchArticle>

Response

        <search:searchArticleResponse>
            <searchResultId code="example-searchresult-1" />
            
            <searchResult>
                <!-- This is the first result for this search. -->
                <previous>0</previous>
                <!-- There are no more search results remaining after the ones
                    contained in this response. -->
                <remaining>0</remaining>

                <element xsi:type="pptype:ArticleSearchResultElement">
                    <!-- In this and further examples, the posps server uses 
                         PZNs for articleIds, which is customary for German
                         pharmacy IT systems but not required by the 
                         specification. -->
                    <articleId code="4479146" />

                    <name>EBENOL Creme</name>
                    <manufacturer>STRATHMANN GMBH&amp;CO KG</manufacturer>
                    <price>749</price><!-- EUR7.49 -->
                    <priceContextSpecific>749</priceContextSpecific>
                    <stock>5</stock>
                    <packaging>
                        <size>25</size>
                        <unit>g</unit>
                    </packaging>
                    <pharmaceutic>
                        <countrySpecific xsi:type="pptype:PharmaceuticArticleDE">
                            <pzn>4479146</pzn>
                        </countrySpecific>
                    </pharmaceutic>
                </element>

                <element xsi:type="pptype:ArticleSearchResultElement">
                    <articleId code="8671142" />

                    <name>MULGATOL Junior Gel</name>
                    <manufacturer>HEMOPHARM GMBH</manufacturer>
                    <price>865</price><!-- EUR8.65 -->
                    <priceContextSpecific>865</priceContextSpecific>
                    <stock>2</stock>
                    <packaging>
                        <size>150</size>
                        <unit>ml</unit>
                    </packaging>
                    <pharmaceutic>
                        <countrySpecific xsi:type="pptype:PharmaceuticArticleDE">
                            <pzn>8671142</pzn>
                        </countrySpecific>
                    </pharmaceutic>
                </element>

                <element xsi:type="pptype:ArticleSearchResultElement">
                    <articleId code="1275791" />

                    <name>ROCHE POSAY Anthelios XL 50+ Creme o.Duftstoff</name>
                    <manufacturer>ROCHE-POSAY DEUTSCHL.</manufacturer>
                    <price>1600</price><!-- EUR16.00 -->
                    <priceContextSpecific>1600</priceContextSpecific>
                    <stock>3</stock>
                    <packaging>
                        <size>50</size>
                        <unit>ml</unit>
                    </packaging>
                    <pharmaceutic>
                        <countrySpecific xsi:type="pptype:PharmaceuticArticleDE">
                            <pzn>1275791</pzn>
                        </countrySpecific>
                    </pharmaceutic>
                </element>

                <element xsi:type="pptype:ArticleSearchResultElement">
                    <articleId code="4208045" />

                    <name>ROCHE POSAY Anthelios 20 Fluide Extreme</name>
                    <manufacturer>ROCHE-POSAY DEUTSCHL.</manufacturer>
                    <price>1475</price><!-- EUR14.75 -->
                    <priceContextSpecific>1475</priceContextSpecific>
                    <stock>1</stock>
                    <packaging>
                        <size>50</size>
                        <unit>ml</unit>
                    </packaging>
                    <pharmaceutic>
                        <countrySpecific xsi:type="pptype:PharmaceuticArticleDE">
                            <pzn>4208045</pzn>
                        </countrySpecific>
                    </pharmaceutic>
                </element>
                
                <!-- In this example, the other two articles are not in stock
                     and therefore not included in the search result because
                     of the <inStock /> condition. -->
            </searchResult>
        </search:searchArticleResponse>

The search result is used to generate the page which shows the articles to the customer. The customer chooses EBENOL Creme by clicking on it an then clicking Add to shopping cart. The visavia reacts by telling the server to add this article as new position. According to the search result, the article has the articleId 4479146.


addSalePosition

Request

<sale:addSalePosition>
    <saleId code="example-1" />
    
    <addPositionData>
        <articleId code="4479146" />
        <amount>1</amount>
    </addPositionData>
    
</sale:addSalePosition>

Response

    <sale:addSalePositionResponse>
        <sale>
            <saleId code="example-1" />

            <!-- The following position was created by the server in response
                to the addSalePosition request. -->
            <position>
                <positionId code="position-1" />
                
                <positionData>
                    <articleId code="4479146" />
                    <name>EBENOL Creme</name>
                    <packaging>
                        <size>25</size>
                        <unit>g</unit>
                    </packaging>
                    <manufacturer>STRATHMANN GMBH&amp;CO KG</manufacturer>
                    <amount>1</amount>
                    <delivered>0</delivered>
                    <articlePrice>749</articlePrice>
                    <positionPrice>749</positionPrice>
                    <vatRate>19</vatRate>
                    <pharmaceutic>
                        <countrySpecific xsi:type="pptype:PharmaceuticPositionDE">
                            <!-- 
                                While the elements of PharmaceuticPositionDE
                                are defined as optional, the visavia needs the
                                data of the following elements to work properly.
                                The server may also send the other elements,
                                which are left out in this example for brevity.
                            -->
                            <pzn>1275791</pzn>
                            <apothekenpflicht>true</apothekenpflicht>
                            <rezeptpflicht>false</rezeptpflicht>
                        </countrySpecific>
                    </pharmaceutic>
                </positionData>
            </position>

            <!-- the total now includes the price of the newly added article -->
            <total>
                <vat>
                    <vatRate>19</vatRate>
                    <price>120</price>
                </vat>
                <total>749</total>
            </total>

        </sale>
    </sale:addSalePositionResponse>

The visavia shows the new shopping cart content and total price to the customer.

The customer changes his mind. He selects the article from the shopping cart and removes it by clicking Delete article. This causes the visavia to call the deleteSalePosition operation.


deleteSalePosition

Request

<sale:deleteSalePosition>
    <saleId code="example-1" />
    <positionId code="position-1" />
</sale:deleteSalePosition>

Response

<sale:deleteSalePositionResponse>
    <sale>
        <saleId code="example-1" />
        
        <!-- the server has deleted the position and reset the total
             price -->
        
        <total>
            <total>0</total>
        </total>
        
    </sale>
</sale:deleteSalePositionResponse>

The shopping cart is now empty.

The customer goes back to the article list. This time he chooses MULGATOL Junior Gel which has an articleId of 8671142. The visavia adds this item by another addSalePosition call.


addSalePosition

Request

<sale:addSalePosition>
    <saleId code="example-1" />
    
    <addPositionData>
        <articleId code="8671142" />
        <amount>1</amount>
    </addPositionData>
    
</sale:addSalePosition>

Response

    <sale:addSalePositionResponse>
        <sale>
            <saleId code="example-1" />

            <!-- The following position was created by the server in response
                to the addSalePosition request. -->
            <position>
                <positionId code="position-1" />
                <positionData>
                    <articleId code="8671142" />
                    <name>MULGATOL Junior Gel</name>
                    <packaging>
                        <size>150</size>
                        <unit>ml</unit>
                    </packaging>
                    <manufacturer>HEMOPHARM GMBH</manufacturer>
                    <amount>1</amount>
                    <delivered>0</delivered>
                    <articlePrice>865</articlePrice>
                    <positionPrice>865</positionPrice>
                    <vatRate>19</vatRate>
                    <pharmaceutic>
                        <countrySpecific xsi:type="pptype:PharmaceuticPositionDE">
                            <pzn>8671142</pzn>
                            <apothekenpflicht>false</apothekenpflicht>
                            <rezeptpflicht>false</rezeptpflicht>
                        </countrySpecific>
                    </pharmaceutic>
                </positionData>
            </position>

            <!-- the total now includes the price of the newly added article -->
            <total>
                <vat>
                    <vatRate>19</vatRate>
                    <price>138</price>
                </vat>
                <total>865</total>
            </total>

        </sale>
    </sale:addSalePositionResponse>

The visavia shows the updated shopping cart.

The customer wants to buy this article and proceeds to the payment page. He chooses to pay cash. The visavia collects the calculated total of EUR8.65 from the customer.

After the customer has paid, the visavia orders the article from the robot using the Order port of the posps server. In the meantime, it shows a "please wait" movie to the customer.


orderArticles

Request

<order:orderArticles>
    <order>
        <article>
            <articleId code="8671142" />
            <positionId code="position-1" />
            <amount>1</amount>
        </article>
    </order>
    
    <posId code="visavia-1" />
    
    <saleId code="example-1" />
    
</order:orderArticles>

Response

<order:orderArticlesResponse>
    <orderId code="order-id-1" />
    
    <saleId code="example-1" />
    
    <articles>
        <article>
            <articleId code="8671142" />
            <positionId code="position-1" />
            <ordered>1</ordered>
            <delivered>0</delivered><!-- the article is still on its way -->
        </article>
    </articles>
    
</order:orderArticlesResponse>

The server response shows that the ordered article is still on its way. The visavia therefore has to call trackOrder to monitor the delivery state of the article.


trackOrder

Request

<order:trackOrder>
    <trackingId>
        <saleId code="example-1" />
    </trackingId>
</order:trackOrder>

Response

<order:trackOrderResponse>
    <articles>
        <article>
            <articleId code="8671142" />
            <ordered>1</ordered>
            <delivered>1</delivered><!-- the article has now been delivered -->
        </article>
    </articles>
    <trackingId>
        <saleId code="example-1" />
    </trackingId>
</order:trackOrderResponse>

Now that the article was delivered to the output tray, the visavia unlocks it so that the customer can take the article. After this has happened, the visavia calls confirmSaleDelivery to tell the server that the article is dispensed to the customer.


confirmSaleDelivery

Request

<sale:confirmSaleDelivery>
    <saleId code="example-1" />
    
    <deliveredPosition>
        <positionId code="position-1" />
        <delivered>1</delivered>
    </deliveredPosition>
    
</sale:confirmSaleDelivery>

Response

    <sale:confirmSaleDeliveryResponse>
        <sale>
            <saleId code="example-1" />

            <position>
                <positionId code="position-1" />
                <positionData>
                    <articleId code="8671142" />
                    <name>MULGATOL Junior Gel</name>
                    <packaging>
                        <size>150</size>
                        <unit>ml</unit>
                    </packaging>
                    <manufacturer>HEMOPHARM GMBH</manufacturer>
                    <amount>1</amount>
                    
                    <!-- the delivered amount was changed by the operation -->
                    <delivered>1</delivered>
                    
                    <articlePrice>865</articlePrice>
                    <positionPrice>865</positionPrice>
                    <vatRate>19</vatRate>
                    <pharmaceutic>
                        <countrySpecific xsi:type="pptype:PharmaceuticPositionDE">
                            <pzn>8671142</pzn>
                            <retailPrice>865</retailPrice>
                            <zuzahlung>0</zuzahlung>
                            <mehrkostenanteil>0</mehrkostenanteil>
                            <apothekenpflicht>false</apothekenpflicht>
                            <rezeptpflicht>false</rezeptpflicht>
                        </countrySpecific>
                    </pharmaceutic>
                </positionData>
            </position>

            <total>
                <vat>
                    <vatRate>19</vatRate>
                    <price>138</price>
                </vat>
                <total>865</total>
            </total>

        </sale>
    </sale:confirmSaleDeliveryResponse>

At this point it is clear that the payment is final and can't be canceled any longer. The visavia therefore invokes the confirmSalePayment operation.


confirmSalePayment

Request

<sale:confirmSalePayment>
    <saleId code="example-1" />
    
    <payment xsi:type="pptype:PaymentCash">
        <!-- the customer has inserted a EUR10.00 bill -->
        <given>1000</given>
        <!-- the visavia has returned the overpaid amount -->
        <returned>135</returned>
    </payment>
    
    <canceled>false</canceled>
</sale:confirmSalePayment>

Response

    <sale:confirmSalePaymentResponse>
        <sale>
            <saleId code="example-1" />

            <position>
                <positionId code="position-1" />
                <positionData>
                    <articleId code="8671142" />
                    <name>MULGATOL Junior Gel</name>
                    <packaging>
                        <size>150</size>
                        <unit>ml</unit>
                    </packaging>
                    <manufacturer>HEMOPHARM GMBH</manufacturer>
                    <amount>1</amount>
                    <delivered>1</delivered>
                    <articlePrice>865</articlePrice>
                    <positionPrice>865</positionPrice>
                    <vatRate>19</vatRate>
                    <pharmaceutic>
                        <countrySpecific xsi:type="pptype:PharmaceuticPositionDE">
                            <pzn>8671142</pzn>
                            <retailPrice>865</retailPrice>
                            <zuzahlung>0</zuzahlung>
                            <mehrkostenanteil>0</mehrkostenanteil>
                            <apothekenpflicht>false</apothekenpflicht>
                            <rezeptpflicht>false</rezeptpflicht>
                        </countrySpecific>
                    </pharmaceutic>
                </positionData>
            </position>

            <total>
                <vat>
                    <vatRate>19</vatRate>
                    <price>138</price>
                </vat>
                <total>865</total>
            </total>

            <!-- The server has added the payment element as a result of the
                 confirmSalePayment call. -->
            <payment>
                <payment xsi:type="pptype:PaymentCash">
                    <given>1000</given>
                    <returned>135</returned>
                </payment>
            </payment>

        </sale>
    </sale:confirmSalePaymentResponse>

The visavia now prints the receipt. It gets the formatted receipt data from the server by invoking createPickupReceipt.

The printer built into the visavia uses a fixed-with font with a maximum of 64 characters per line. The server is therefore configured to generate a receipt of the posps type FixedWidthPrintMarkup with a maximum line width of 64.


createSaleReceipt

Request

<sale:createSaleReceipt>
    <saleId code="example-1" />
</sale:createSaleReceipt>

Response

        <sale:createSaleReceiptResponse>
            <receipts>
                <receipt xsi:type="pptype:FixedWidthPrintMarkup">
<dw>Rowa Pharmacy</dw>
<n>
Rowastraße 1
53539 Kelberg
www.rowa.de

Receipt No:     1234                           Date: 2012/03/13
Point of sale:     1                           Time: 08:46

Article                      Unit Price        Amount Delivered
---------------------------------------------------------------

MULGATOL Junior Gel        150 ml EUR 8.65        1       1         

---------------------------------------------------------------

Total net  EUR  8.65
VAT 19%    EUR  1.38      
Paid:      EUR 10.00
Returned:  EUR  1.35

VAT identification number: DE00000000
</n>
<b>www.mediterminal.de</b>
                </receipt>
            </receipts>
        </sale:createSaleReceiptResponse>

This completes the sale from the point of view of the posps interface. The visavia informs the customer that he can collect his articles, change and receipt, shows a goodbye screen and calls closeSale to finish with the sale.


closeSale

Request

<sale:closeSale>
    <saleId code="example-1"/>
</sale:closeSale>

Response

<sale:closeSaleResponse />