Shopkeeper Micro-capability¶
Jumpmind Commerce's Shopkeeper Micro-capability supports the following functions:
- Remote Manager Overrides
- Real-time Sales Data Display
- Real-time Device Transaction View
Architecture¶
Shopkeeper consists of a Java server and Angular typescript client like most JMC services. However, unlike most JMC services, Shopkeeper's state management is done via an NGXS integration on the client side, NOT via a Java state manager. These states are populated with data via REST calls to remote (or local) JMC service endpoints.
Additionally, to support real-time data, Shopkeeper's server supports a two-way gRPC connection to JMC's State Relay. The server makes the gRPC connection, while the client is notified of / allowed to pass updates to this stream via a websocket connection to the server. Both the websocket and gRPC connection are established when the Shopkeeper client application is initialized.
The State Relay¶
The JMC State Relay application is necessary to facilitate bi-directional realtime communication between the POS and Shopkeeper.
The State Relay is REQUIRED to access the full breadth of Shopkeeper functionality.
The State Relay is typically run centrally with Shopkeeper running either centrally, or in the store. Shopkeeper and the POS are designed to auto-connect to the State Relay, provided the configurations in the "Technical Configuration" section are setup correctly.
Enablement as a Microcap (Integrated)¶
The Integrated Microcap mode will enable bidirectional access between the Commerce application and the Shopkeeper module. Tapping the button on Commerce's Home screen will take you to Shopkeeper's dashboard.
Enabling Integrated (Microcap) Mode¶
Integrated mode can be enabled by exposing a "Shopkeeper" button on the Commerce home screen.
Integration Checklist¶
- [ ] Add a row to
ctx_buttonconfigured as follows:
| button_group_id | button_id | button_name | button_type | button_value | enabled |
|---|---|---|---|---|---|
| home | LaunchShopkeeper | key:home:home.shopkeeper | action | LaunchShopkeeper | 1 |
Configuration¶
The Shopkeeper micro-cap's functionality is driven by a combination of database data and Spring context configuration, the latter of which supplies both technical and business rule parameters.
Technical Configuration¶
The following application-*.yml parameters govern technical behavior for the Shopkeeper module:
| Key | Purpose | App | Customization Required? |
|---|---|---|---|
| openpos.micro-caps.configs.shopkeeper.server-url | names the URL of the server hosting Shopkeeper services when running in Integrated mode | POS | Y |
| openpos.micro-caps.configs.shopkeeper.remote-entry | names and locates the script invoked to serve the Shopkeeper micro-cap when accessed from another application | POS | Y |
| openpos.state-relay.enabled | enable the state relay to transmit data | POS, Shopkeeper | Y (Default is false for POS) |
| openpos.state-relay.target | the remote host and port of the state relay for the POS and Shopkeeper to connect to | POS, Shopkeeper | Y |
Checklist¶
- [ ] Configure the URL of the server hosting Shopkeeper services
- [ ] Configure the host and port at which the
remoteEntry.jsscript serving the Shopkeeper micro-cap is invokable - [ ] Ensure the state relay is enabled on all valid registers and Shopkeeper
- [ ] Ensure the POS and Shopkeeper are targeting the correct address of the state relay
Data¶
The following database tables must, at a minimum, be populated as described in order to enable all front- and back-end features exposed by the Shopkeeper micro-cap. These may be populated directly (via data scripts) or through integrations with external providers (via e.g. SymmetricDS).
| Table | Qualifier | Features Requiring | Purpose |
|---|---|---|---|
dev_device |
Shopkeeper real-time device state display | Provides Shopkeeper a list of devices to monitor. An devices in this table matching Shopkeeper's business unit ID will be flagged to be monitored. | |
sk_sales_ticker |
Sales Tickers | Provides definitions for Shopkeeper's Sales tickers on its Sales widget. | |
sk_sales_timeline |
Sales Timelines | Provides definitions for lines on Shopkeeper's timeline graph on its Sales widget. |
Checklist¶
- [ ] Populate requisite tables with customer-specific data
Data Model¶
Additional info regarding Data models can be seen in our Swagger output or the DataModel.md file. Swagger provides detailed descriptions of tables and columns that may be of assistance to gain a good conceptual understanding of the models used here.
erDiagram
sk_sales_ticker {
string ticker_id
string title
string subtitle
int polling_interval
}
sk_sales_timeline {
string timeline_id
string title
boolean bind_to_right_axis
}
sk_notification {
string id
string notification_type
boolean resolved
string sent_by_username
string resolved_by_username
date sent_time
date resolved_time
string device_id
string message
}
*Note: Shopkeeper models have no relation to each other.
APIs¶
Shopkeeper has two main API service implementations:
- Shopkeeper Device Management
- Shopkeeper Statistics
APIs are invoked via the rest/shopkeeper path.
If you'd like to see detailed request and response information, please take a look at our Swagger API page. The information below is designed to be a quick reference.
Overriding Endpoint Service Calls¶
Several endpoint service calls in Shopkeeper are implemented with base functionality, but are designed to be overridden based on your own specific data and display requirements.
The "Intended to be Overridden" column in the subsequent tables should clarify which service calls these correspond to:
- "YES" implies the endpoint has some level of out-of-the-box functionality, but is ultimately intended to be customized.
- "NO" implies the endpoint is NOT designed to be overridden.
- "OPTIONAL" implies the endpoint can be overridden, but the base functionality is intended to be serviceable to most clients.
Device Management /device-management¶
The Device Management API is designed to save, recall, and handle information regarding devices, notifications, or other device-specific things relevant to Shopkeeper.
The service has the following service calls:
| Service Call | HTTP | Path | Purpose | Intended to be overridden |
|---|---|---|---|---|
getDeviceIds() |
GET |
rest/shopkeeper/device-management/deviceids/{businessUnitId}/{appId} |
Obtain a list of devices for Shopkeeper to monitor. | OPTIONAL |
getResolvedNotifications() |
POST |
rest/shopkeeper/device-management/notifications/getResolved |
Obtain a list of resolved notifications. | NO |
saveNotifications() |
PUT |
rest/shopkeeper/device-management/notifications/save |
Save a notification | NO |
respondToManagerOverrideRequest() |
POST |
rest/shopkeeper/device-management/{deviceId}/manager-override/{requestId} |
Respond to a manager override request | NO* |
*respondToManagerOverrideRequest() is not designed to be overridden except in the case that a client is not using JMC
POS.
Statistics /statistics¶
The Statistics API is designed to provide models and data for the various Sales displays on Shopkeeper.
The service has the following service calls:
| Service Call | HTTP | Path | Purpose | Intended to be overridden |
|---|---|---|---|---|
getTickers() |
GET |
rest/shopkeeper/statistics/tickers/{businessUnitId} |
Obtain a list of sales tickers for Shopkeeper to display on its Sales widgets. Tickers are defined by SK_SALES_TICKER |
NO |
getTickerValue() |
POST |
rest/shopkeeper/statistics/tickerData/{businessUnitId}/{tickerId} |
Obtain data for a particular ticker. Is called periodically based on pollingInterval supplied in ticker model |
YES |
saveTimelines() |
PUT |
rest/shopkeeper/statistics/timelines/{businessUnitId} |
Obtain a list of timelines for the Shopkeeper timeline graph. There is no limit to timelines, but only two y-axes are available. Timelines are defined by SK_SALES_TICKER |
NO |
getTimelineData() |
POST |
rest/shopkeeper/statistics/timelineValues/{businessUnitId}/{timelineId} |
Obtain a set of data points for the given timeline. This is called once at screen creation, and not periodically (unlike a polling Ticker). | YES |
getDailyGoalValue() |
POST |
rest/shopkeeper/statistics/dailyGoal/{businessUnitId}/current |
Obtain the current daily goal value.This is displayed on the Sales gauge. There is no requirement for this to be a "daily" goal. Any value will suffice. This is polled periodically by Shopkeeper. | OPTIONAL (Default requires sls_trans_summary integration) |
getDailyGoalTarget() |
POST |
rest/shopkeeper/statistics/dailyGoal/{businessUnitId}/target |
Obtain the current target goal value. This is displayed on the Sales gauge. This value is NOT polled, and will only be requested by Shopkeeper on screen creation. | YES |
Implementing Additional Manager Override Context¶
Shopkeeper supports additional context for several manager override operations right out of the box. Additional context
can be provided by implementing additional IManagerOverrideParams and IManagerOverrideParamBuilder classes in the POS
project. See manager_override_context.md for more information.
FAQ¶
This FAQ contains common questions that may come up during the implementation process of Shopkeeper. If you find you have a question that is not listed here, please add it in if you receive an answer - even if the question is answered somewhere in this document already. Others may have been confused or glossed over the same information.
Q: How do I set my own value for a Ticker, Timeline, or Gauge Data?¶
The preferred way to pass data to a Ticker or Timeline is to create a new IShopkeeperTickerDataAggregator or IShopkeeperTimelineDataAggregator implementation.
This will allow you to pass data to Shopkeeper in a way that is both efficient and easy to maintain:
1. Add a new row to the sk_sales_ticker or sk_sales_timeline table with a unique ticker_id or timeline_id
2. Create a new implementation of IShopkeeperTickerDataAggregator or IShopkeeperTimelineDataAggregator and add it to the Spring context (add it to your project)
3. Implement the getAggregatorKey() method to return the ticker_id or timeline_id you created in step 1
4. Implement the getTickerData() or getTimelineData() method to return the data you want to display. You may utilize the @RequiredArgsConstructor tag to pull in any necessary JMC Microservices, or reach out to external services at this point.
To override the gauges, you can override the following endpoints depending on which gauge you'd prefer to setup data for:
- ShopkeeperGetAverageBasketSizeEndpoint for the average basket size graph
- ShopkeeperGetConversionRateEndpoint for the conversion rate display
- ShopkeeperGetDailyGoalValueEndpoint for the daily goal display (the current value)
- ShopkeeperGetDailyGoalTargetEndpoint for the daily goal display (the target value)
- ShopkeeperGetCoverageDataEndpoint for the coverage graph
To do this, you will need to override the endpoint:
- Create a new endpoint for your service method with a custom
implementationvalue. See our "How to add new implementations of existing service methods" in our microservices.md file. - Use the
@Autowiredtag to pull in any relevant JMC Microservices to your new endpoint - Utilize the microservices to implement your own custom logic
As an alternative, your endpoint can also make a remote call to another service. The ticker data lookup happens asynchronously, so the app will not be held up by lengthy response times.
Q: Are there any restrictions on the data I provide via the "data" and "value" Statistics aggregators / endpoints?¶
There are no enforced limits on this data, but all data from "value" endpoints is displayed as currency on the application UI. Additionally, timeline data is expected to adhere to one x-axis scale and at most two y-axis scales.
Aside from hard restrictions, keep in mind the polling rate set on tickers. Expensive operations done frequently can become problematic quickly. The tickers will always request new data upon rendering as well, regardless of their polling rate.
Q: Shopkeeper does not show any devices?¶
Shopkeeper will look in the dev_device table to find all entries that match a pos app ID and the business unit ID
Shopkeeper is running on (You should be able to see this on Shopkeeper's dashboard). Ensure there are valid devices in this table.
Q: Shopkeeper shows several devices it's monitoring, but the devices do not appear to be updating in Shopkeeper?¶
Shopkeeper handles device state updates and manager overrides via the JMC State Relay application. Ensure the openpos.state-relay.enabled and openpos.state-relay.target are set correctly
on all registers and Shopkeeper instances. Additionally, ensure the device IDs shown on Shopkeeper match the device IDs you're
trying to monitor, and that the monitored devices are set to the pos app ID.
Q: Shopkeeper was monitoring devices, but no longer appears to be?¶
Shopkeeper's client makes a websocket connection to its server to receive and pass updates to the gRPC protocol that the state relay listens / sends on. Restarting the Shopkeeper client application will attempt to reconnect to this websocket.
If this issue is persistent, consider filing a bug report on our Issue Tracker.
Q: The State Relay doesn't appear to be doing anything?¶
The state relay, by default, is turned off on JMC POS configurations. Ensure openpos.state-relay.enabled is set to true on all relevant devices
Q: Can I show a relative date on my tickers like you do in the default configuration?¶
Shopkeeper knows how to compute a relative date for several token values. You can set the subtitle data field
in sk_sales_ticker to one of the following values to get the corresponding computed date:
%DATE%(Today)%LASTWEEK%(Last Week)%LASTYEAR%(Last Year)
Q: How do I decline a manager override on Shopkeeper?¶
You cannot currently decline a manager override on Shopkeeper. You can only dismiss it from view.
If you'd like to see this feature in a future release, consider making a Feature Request on our issue tracker.
Q: What are the relationships between Shopkeeper's data tables?¶
Shopkeeper's data tables are isolated from each other and have no X:X relationships with each other.
Q: I'd like to override one of the endpoint invocations you said not to override above. Can I do that?¶
It's strongly recommended that you refrain from overriding any service calls not recommended to be overridden. These calls are generally simple database lookups of visual models the UI will use to display information. Overriding them can cause unneeded complexity and obscure bugs.