AndreasFagschlunger / O2Xfs

Java API for accessing CEN/XFS API, EMV Level 2 Kernel
47 stars 28 forks source link

Can I Use CDMService for CIM ? #41

Closed azdafirmansyah closed 7 years ago

azdafirmansyah commented 7 years ago

Hi All,

Is it possible when use CDMService for CIM ? where I can find service for CIM ? because I didn't find CIMService in at.o2xfs.xfs.service project.

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hi @azdafirmansyah

No, you can't use CdmService for CIM commands, even if they share some common commands. And you are right, there is no CimService implementation yet. But at.o2xfs.xfs and o2xfs-xfs3 projects contain all necessary data elements. So nothing should stop you from writing your own CimService class and commands.

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger,

I try to Cash Count use my own CIMService but I still got this error :

CimExecuteCommand.CASH_UNIT_COUNT = at.o2xfs.xfs.XfsServiceException: WFS_ERR_INVALID_COMMAND(-20)

CimExecuteCommand.CASH_IN = at.o2xfs.xfs.cim.CimException: NOCASHINACTIVE(-1326)

CimExecuteCommand.CASH_IN_START = at.o2xfs.xfs.cim.CimException: UNSUPPOSITION(-1308)

Here is my code : `XfsExecuteCommand executeCommandCount = new XfsExecuteCommand(cimService, CimExecuteCommand.CASH_UNIT_COUNT,XfsWord.valueOf(Position.NULL));

WFSResult wfsResultCount = null; try { wfsResultCount = executeCommandCount.call(); System.out.println(wfsResultCount.getSize()); } catch (XfsException e) { e.printStackTrace(); } finally { if (wfsResultCount != null) { XfsServiceManager.getInstance().free(wfsResultCount); } }`

Can you suggest why I got this error ?

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hello @azdafirmansyah

You can't execute (WFS_CMD_CIM_)CASH_IN unless you successfully executed (WFS_CMD_CIM_)CASH_IN_START. That's what NOCASHINACTIVE is saying: There is no cash-in transaction active.

And CASH_IN_START fails with UNSUPPOSITION; The position specified is not supported.. So first step would be to query the capabilities (CimInfoCommand.CAPABILITIES, Capabilities3.class) for the available positions. And then execute CASH_IN with a valid CashInStart3 object.

Regards, Andreas Fagschlunger

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger,

I still got error when try to deposit. .Below link my test code to do this squence test :

  1. Init Device
  2. Open And Register
  3. Open Shutter
  4. Close Shutter
  5. Cash Count
  6. Deposit (Notes go to Recycle Cassette) https://drive.google.com/file/d/0B3NRikF5MB_2MXdUc2puREhBX0E/view?usp=sharing

I have a few question regarding this :

  1. Based on your explanation above, the sequence must follow :
    • Check Capabilities Capabilities3 capabilities1 = cimService.getCapabilities();
      XfsInfoCommand commandInfo = new XfsInfoCommand(cimService, CimInfoCommand.CAPABILITIES); WFSResult wfsResultInfo = null; try { wfsResultInfo = commandInfo.call();
      -->is it true like above ?
    • CASH_IN_START XfsExecuteCommand executeCommandCashInStart = new XfsExecuteCommand(cimService, CimExecuteCommand.CASH_IN_START, XfsWord.valueOf(Position.NULL)); WFSResult wfsResultCashInStart = null; try { wfsResultCashInStart = executeCommandCashInStart.call(); -->is it true like above ? When no cash in shutter, this code get error result and cannot do next comment for CimExecuteCommand.CASH_IN. But if I put notes inside shutter, notes go to reject cassette.
      • CASH_IN XfsExecuteCommand executeCommandCashIn = new XfsExecuteCommand( cimService, CimExecuteCommand.CASH_IN, XfsWord.valueOf(Position.NULL)); WFSResult wfsResultCashIn = null; try { wfsResultCashIn = executeCommandCashIn.call();
        -->is it true like above ? when shutter close, there is no action I can do. Because while debug stuck here but no error.
      • CashInStart3 How to use this.

For complete code you can download here : https://drive.google.com/file/d/0B3NRikF5MB_2MXdUc2puREhBX0E/view?usp=sharing

Sorry I ask too many question.

Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hello @azdafirmansyah

The reason for executing CimInfoCommand.CAPABILITIES is, to get information on what machine you're dealing with. The XFS API supports a wide variety of depository devices, so use the information provided in Capabilities3 to act accordingly.

I would also suggest to take a look at the XFS specifications in general: https://www.cen.eu/work/areas/ICT/eBusiness/Pages/WS-XFS.aspx

And Part 15 describes the Cash-In Module API in detail, e.g. XFS 3.10: ftp://ftp.cenorm.be/CWA/CEN/WS-XFS/CWA15748/CWA15748-15-2008-July.pdf

Chapter 7 describes common transaction flows. You can see that OPEN_SHUTTER can only be executed if the devices need explicit shutter control and it's only valid during a successful transaction, which means CASH_IN_START must be successful.

And this can't work:

new XfsExecuteCommand<CimExecuteCommand>(cimService, CimExecuteCommand.CASH_IN_START, XfsWord.valueOf(Position.NULL));

Since the (WFS_CMD_CIM_)CASH_IN_START execute command expects a pointer to a WFSCIMCASHINSTART structure as input parameter, this would be CashInStart3 object in O²Xfs.

So the right thing would be to create a CashInStart3 object with all necessary values set and use this object as a parameter to the XfsExecuteCommand.

To create a CashInStart3 object it's better to create a inner Builder class like in Dispense3, since with public constructors and set-methods, the object isn't immutable which is not clean code.

Best regards, Andreas Fagschlunger

azdafirmansyah commented 7 years ago

Hello @AndreasFagschlunger,

I already success to Open and Close shutter. But I try without call CASH_IN_START. I still got failed while call CASH_IN_START.

Can you suggest me :

  1. How to call CASH_IN_START
  2. How to use CashInStart3
  3. Below my test code snippet to check available position. based on this code I got result "INFRONT and OUTREAR". Is it my test code correct ? if correct how to use this avilable position?

Capabilities3 capabilities1 = cimService.getCapabilities(); Set<at.o2xfs.xfs.cim.Position> pos = capabilities1.getPositions(); Iterator itr = pos.iterator(); while (itr.hasNext()) {
at.o2xfs.xfs.cim.Position sPosition = (at.o2xfs.xfs.cim.Position) itr.next(); String sName = sPosition.name();
}

Best Regards, Azda Firmansyah

AndreasFagschlunger commented 7 years ago

Hello @azdafirmansyah

First add a inner Builder class to CashInStart3:

public class CashInStart3 extends Struct {

    public static class Builder {

        private int tellerId;
        private boolean useRecycleUnits;
        private Position outputPosition;
        private Position inputPosition;

        public Builder() {
            tellerId = 0;
            useRecycleUnits = false;
            outputPosition = Position.NULL;
            inputPosition = Position.NULL;
        }

        public Builder tellerId(int tellerId) {
            this.tellerId = tellerId;
            return this;
        }

        public Builder useRecycleUnits(boolean useRecycleUnits) {
            this.useRecycleUnits = useRecycleUnits;
            return this;
        }

        public Builder outputPosition(Position outputPosition) {
            this.outputPosition = outputPosition;
            return this;
        }

        public Builder inputPosition(Position inputPosition) {
            this.inputPosition = inputPosition;
            return this;
        }

        public CashInStart3 build() {
            return new CashInStart3(this);
        }
    }
    ...
    protected CashInStart3(Builder builder) {
        this();
        allocate();
        tellerID.set(builder.tellerId);
        useRecycleUnits.set(builder.useRecycleUnits);
        outputPosition.set(builder.outputPosition);
        inputPosition.set(builder.inputPosition);
    }

This allows you to actually build a CashInStart3 object with parameters using the builder pattern. Since you posted your IN-/OUT-Positions, this should work:

CimService cimService = serviceManager.openAndRegister("CIM", CimService.class);

CashInStart3 cashInStart = new CashInStart3.Builder()
        .inputPosition(Position.INFRONT)
        .outputPosition(Position.OUTREAR)
        .build();
XfsExecuteCommand<CimExecuteCommand> executeCommand = new XfsExecuteCommand<CimExecuteCommand>(cimService,
        CimExecuteCommand.CASH_IN_START, cashInStart);
WFSResult wfsResult = null;
try {
    wfsResult = executeCommand.call();
} finally {
    if(wfsResult != null) {
        serviceManager.free(wfsResult);
    }
}

Best regards, Andreas Fagschlunger

azdafirmansyah commented 7 years ago

Hi @AndreasFagschlunger,

Thanks