
"event": { "eventName": "SHOW_ADD_INFO", "eventPayload" : { "message" : "I am an event payload message" }}
@Override
public void startup() {
AdditionalInfoDao.getInstance().setupTable();
BackendEventHandler.getInstance().registerEventHandler();
super.startup();
}
buildElements() {
// all our ui components will be bound to a datamodel so that we can easily access the
// values of the cashiers input
this.model1 = new cco.InputModel();
this.modelAmount = new cco.InputModel();
this.modelDecimal = new cco.InputModel();
// the option model is like a select box so we need to add options to select.
this.selectModel = new cco.OptionModel();
this.selectModel.addOption(new cco.Option('option1', 'First option'));
this.selectModel.addOption(new cco.Option('option2', 'Second option'));
this.selectModel.addOption(new cco.Option('option3', 'Third option'));
this.selectModel.selectFirstOption();
// we are creating 2 arrays each containing all ui components for each ribbon.
this.ribbonOneElements = [{
index: [0, 0],
hspan: 8,
vspan: 8,
content: {
// this is our first LabelComponent
component: cco.LabelComponent,
props: {
text: 'Additional Field 1:',
class: 'tableCellLayout'
}
}
}, {
index: [0, 10],
hspan: 20,
vspan: 8,
content: {
// this is our first InputFieldComponent
component: cco.InputFieldComponent,
props: {
// bound the datamodel
id: 'first',
model: this.model1,
class: 'tableCellLayout',
autoSetPrimaryTarget: true
}
}
}, {
index: [16, 0],
hspan: 8,
vspan: 8,
content: {
// this is our second LabelComponent
component: cco.LabelComponent,
props: {
text: 'Additional Field 2:',
class: 'tableCellLayout'
}
}
}, {
index: [16, 10],
hspan: 20,
vspan: 8,
content: {
component: cco.InputFieldComponent,
props: {
id: 'second',
model: this.modelAmount,
class: 'tableCellLayout',
numeric: true,
autoSetPrimaryTarget: true
}
}
}];
this.ribbonTwoElements = [{
index: [0, 0],
hspan: 8,
vspan: 8,
content: {
component: cco.LabelComponent,
props: {
text: 'Additional Field 3:',
class: 'tableCellLayout'
}
}
}, {
index: [0, 10],
hspan: 20,
vspan: 8,
content: {
component: cco.InputFieldComponent,
props: {
id: 'third',
model: this.modelDecimal,
numeric: true,
class: 'tableCellLayout',
autoSetPrimaryTarget: true
}
}
}, {
index: [16, 0],
hspan: 8,
vspan: 8,
content: {
component: cco.LabelComponent,
props: {
text: 'Additional Field 4:',
class: 'tableCellLayout'
}
}
}, {
index: [16, 10],
hspan: 20,
vspan: 8,
content: {
// For our selection model we use the ui component called SelectComponent
component: cco.SelectComponent,
props: {
model: this.selectModel,
class: 'tableCellLayout'
}
}
}];
}
createRibbonOneConfiguration() {
// define which text the buttons should show
let buttons = [{
content: 'Tab1'
}, {
content: 'Tab2'
}];
// creating a GenericInputConfiguration containing a GridLayoutComponent
return new cco.GenericInputConfiguration('RibbonForm', '2', 'Component', null, null, cco.GridLayoutComponent, {
props: {
// set this so elements in the gridlayout can overlap. So elements in ribbon 1 and 2 can have the
// same position.
overlappingElements: true,
elements: [{
index: [0, 0],
hspan: 25,
vspan: 15,
content: {
// this is the ui element we are using for the ribbons.
component: cco.StatefulButtonBarComponent,
props: {
// setting the buttons as prop and also our datamodel.
buttons: buttons,
class: 'light',
populateModel: true,
model: this.ribbonSelectModel
}
}
}, {
index: [30, 0],
hspan: 25,
vspan: 10,
content: {
// our father gridlayout will contain another
// gridlayout. One per ribbon.
component: cco.GridLayoutComponent,
props: {
static: {
elements: this.ribbonOneElements
},
// setting the dynamic property to change the css class
// based on the selection of the ribbon.
dynamic: this.dynamicPropsRibbonOne,
cols: 100,
rows: 100
}
}
}, {
index: [30, 0],
hspan: 25,
vspan: 10,
content: {
component: cco.GridLayoutComponent,
props: {
static: {
elements: this.ribbonTwoElements
},
dynamic: this.dynamicPropsRibbonTwo,
cols: 100,
rows: 100
}
}
}],
cols: 100,
rows: 100
}
});
}
if (Object.keys(event.getPayload()).length !== 0) {
// set the values we got from the backend to our datamodels
this.model1.value = event.getPayload().addFld1;
this.modelAmount.value = event.getPayload().addFld2;
this.modelDecimal.value = event.getPayload().addFld3;
this.selectModel.setSelectedOptionKey(event.getPayload().addFld4);
}
this.eventBus.push('SHOW_GENERIC_INPUT', {
configuration: [
this.createRibbonOneConfiguration(),
],
title: 'Additional Info for customer ' + this.receiptStore.receiptModel.businessPartner.externalID,
showKeyboardSwitchButton: true,
keyboardType: 'keyboard',
widthFactor: 0.8,
heightFactor: 0.8
});
// we are also creating something called DynamicProperties so we can hide ui components when not used e.g.
// when the cashier uses ribbon the first ribbon so all elements on the second ribbon will not be visible.
this.dynamicPropsRibbonOne = new cco.DynamicProperties({
class: this.ribbonSelectModel.getSelected() !== 0 ? 'pluginRibbonHidden' : ''
});
// so we are basically setting a css class when our datamodel behind the ribbons has a certain value.
// the css class can be found in our blogpluginpart5.css
// With the Dynamic Properties you can set all properties of a component. e.g. changing the text, the height, ...
// of a ui component dynamically.
this.dynamicPropsRibbonTwo = new cco.DynamicProperties({
class: this.ribbonSelectModel.getSelected() !== 1 ? 'pluginRibbonHidden' : ''
});
// we are setting an observer to the ribbonSelectModel so we can react
// when the cashier clicks on another ribbon
this.ribbonSelectModel.addObserver({
modelChanged: (inputModel) => {
this.dynamicPropsRibbonOne.setAndEmitPropertiesIfChanged({
class: inputModel.getSelected() !== 0 ? 'pluginRibbonHidden' : ''
});
this.dynamicPropsRibbonTwo.setAndEmitPropertiesIfChanged({
class: inputModel.getSelected() !== 1 ? 'pluginRibbonHidden' : ''
});
}
});
.pluginRibbonHidden {
display: none;
}
// in the validate function we can implement checks to have mandatory field checks etc.
cco.GridLayoutComponent.prototype['validate'] = () => {
if (this.model1.value === '' || this.model1.value === 'MANDATORY') {
this.eventBus.push('SHOW_MESSAGE_BOX', {
'title': this.translationStore.getTranslation('ADD_FLD1_MND', this.user.getLanguageCode()),
'message': this.translationStore.getTranslation('ADD_FLD1_MND', this.user.getLanguageCode())
});
return false;
}
return true;
};
this.eventBus.push('SHOW_GENERIC_INPUT', {
configuration: [
this.createRibbonOneConfiguration(),
],
title: 'Additional Info for customer ' + this.receiptStore.receiptModel.businessPartner.externalID,
showKeyboardSwitchButton: true,
keyboardType: 'keyboard',
widthFactor: 0.8,
heightFactor: 0.8,
callback: (positive) => {
if (positive) {
let customerId = this.receiptStore.receiptModel.businessPartner.externalID;
let addFld1 = this.model1.value;
let addFld2 = Math.trunc(this.modelAmount.value);
let addFld3 = this.modelDecimal.value.replace(',', '.');
let addFld4 = this.selectModel.getSelectedOptionKey();
this.pluginService.backendPluginEvent('SAVE_ADDITIONAL_CUSTOMER_DATA', {
'customerId': customerId,
'addFld1': addFld1,
'addFld2': addFld2,
'addFld3': addFld3,
'addFld4': addFld4
});
}
}
});
case "SAVE_ADDITIONAL_CUSTOMER_DATA":
customerId = payload.getString("customerId");
String addFld1 = payload.getString("addFld1");
int addFld2 = payload.getInt("addFld2");
Double addFld3 = payload.getDouble("addFld3");
String addFld4 = payload.getString("addFld4");
logger.info("Got data from ui");
AdditionalInfoDto newDto = new AdditionalInfoDto(customerId, addFld1, addFld2, BigDecimal.valueOf(addFld3), addFld4);
AdditionalInfoDao.getInstance().save(newDto);
break;
public class AdditionalInfoPrintJobBuilder extends BasePrintJobBuilder {
private static final Logger log = Logger.getLogger(AdditionalInfoPrintJobBuilder.class);
private static AdditionalInfoPrintJobBuilder instance;
public static synchronized AdditionalInfoPrintJobBuilder getInstance() {
if (instance == null) {
instance = new AdditionalInfoPrintJobBuilder();
}
return instance;
}
private AdditionalInfoPrintJobBuilder() {
super();
}
@Override
protected boolean needsMerchantCopy(PrintTemplateEntity printTemplateEntity, Object o, CDBSession cdbSession, boolean b) {
return false;
}
@Override
protected boolean isTemplateEnabledForSpecificBuilder(PrintTemplateEntity printTemplateEntity, Object o, CDBSession cdbSession, boolean b) {
return true;
}
@Override
protected void mergeTemplateWithSpecificData(Map<String, Object> map, PrintTemplateEntity printTemplateEntity, Object o, CDBSession cdbSession, boolean b) throws IOException, TemplateException {
log.fine("Add data to map");
AdditionalInfoDto additionalInfoDto = (AdditionalInfoDto) o;
map.put("addInfo", additionalInfoDto);
}
@Override
protected void addSpecificSelectableDataStructure(SelectableDataStructure selectableDataStructure) {
SelectableDataStructure additionalInfoDataStructure = new SelectableDataStructure("AdditionalInfo", SelectableDataStructure.TYPE_LIST, "AdditionalInfo");
this.addSubelementToSelectableStructure(additionalInfoDataStructure, "CustomerId", SelectableDataStructure.TYPE_STRING, "CustomerId");
this.addSubelementToSelectableStructure(additionalInfoDataStructure, "addFld1", SelectableDataStructure.TYPE_STRING, "AddFld1");
this.addSubelementToSelectableStructure(additionalInfoDataStructure, "addFld2", SelectableDataStructure.TYPE_INT, "AddFld2");
this.addSubelementToSelectableStructure(additionalInfoDataStructure, "addFld3", SelectableDataStructure.TYPE_DECIMAL, "AddFld3");
this.addSubelementToSelectableStructure(additionalInfoDataStructure, "addFld4", SelectableDataStructure.TYPE_STRING, "AddFld4");
selectableDataStructure.addSubelement("AdditionalInfo", additionalInfoDataStructure);
}
private void addSubelementToSelectableStructure(SelectableDataStructure parent, String name, String dataType, String descriptionKey) {
SelectableDataStructure childElement = new SelectableDataStructure(name, dataType, descriptionKey);
parent.addSubelement(name, childElement);
}
@Override
public String getDescription() {
return PluginPropertiesConstants.ADDITIONAL_INFO_PRINT_JOB_BUILDER_DESC;
}
@Override
public boolean isResponsibleForDataSource(Object o) {
return o instanceof AdditionalInfoDto;
}
}
@Override
public void startup() {
AdditionalInfoDao.getInstance().setupTable();
BackendEventHandler.getInstance().registerEventHandler();
addPrintJobBuilder();
super.startup();
}
private void addPrintJobBuilder() {
PrintJobManager.INSTANCE.addPrintJobBuilders(AdditionalInfoPrintJobBuilder.getInstance());
}
@Override
public void startup() {
AdditionalInfoDao.getInstance().setupTable();
BackendEventHandler.getInstance().registerEventHandler();
addPrintJobBuilder();
deployPrintTemplate();
super.startup();
}
private void deployPrintTemplate() {
try {
String templateFileName = PluginPropertiesConstants.ADDITIONAL_INFO_PRINT_TEMPLATE + ".xsl";
extractResource("/resources/" + templateFileName, CConfig.getPrintTemplatePath(), false);
} catch (WrongUsageException ex) {
log.severe(PluginPropertiesConstants.EXCEPTION_PRINT_TEMPLATE_COULD_NOT_BE_DEPLOYED);
}
}
public void extractResource(String resName, String path, boolean overwrite) throws WrongUsageException {
InputStream oIn = this.getClass().getResourceAsStream(resName);
if (null != oIn) {
try {
String outName = resName.substring(resName.lastIndexOf("/"));
String fileName = path + File.separator + outName;
File oFl = new File(fileName);
if (!oFl.exists() || overwrite) {
OutputStream oOut = new FileOutputStream(oFl);
IOUtils.copy(oIn, oOut);
oOut.close();
}
oIn.close();
} catch (IOException oX) {
throw new WrongUsageException("Error extracting: " + oX.getMessage());
}
} else {
throw new WrongUsageException("Could not find resource '" + resName + "'.");
}
}
@PluginAt(pluginClass = PrintReceiptPosService.class, method = "printReceipt", where = PluginAt.POSITION.AFTER)
public Object onReceiptPrinted(Object proxy, Object[] args, Object ret, StackTraceElement caller) {
ReceiptEntity receipt = (ReceiptEntity) args[0];
if (null != receipt.getBusinessPartner()) {
AdditionalInfoDto addInfo = AdditionalInfoDao.getInstance().findOne(receipt.getBusinessPartner().getExternalId());
if (addInfo.getCustomerId() != null) {
triggerPrint(addInfo, receipt.getCountPrintouts() > 1);
}
}
return ret;
}
private void triggerPrint(AdditionalInfoDto additionalInfoDto, boolean isReprint) {
try (CDBSession session = CDBSessionFactory.instance.createSession()) {
List<PrintJob<?>> printJobs = PrintJobManager.INSTANCE.createPrintJobs(additionalInfoDto, session, isReprint);
PrintEngine.INSTANCE.print(printJobs, false);
} catch (IOException | WrongUsageException | ParserConfigurationException | SAXException | TemplateException | TransformerException | InterruptedException e) {
e.printStackTrace();
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.