Wiki

Clone wiki

myob-api / Home

200x47-white-bg.png

Welcome

This API provides a java interface to interact with the MYOB API.

Main characteristics

  • Supports desktop and cloud versions of MYOB
  • All entity classes have been translated to java from the 'Contracts' package of the .NET c# SDK provided by MYOB.
  • Two transport classes have been implemented, one using the Apache Http Client library, the other one using plain Java SE (HttpUrlConnection).
  • Google Gson is used for java to json serialization.
  • API supports CDI 1.2 and uses Weld-SE in SE environments.
  • Apache 2 Licensed

Support by donation at http://irc.anahata.uno

Loving developers: http://anahata.net.au

Maven

The artifacts are deployed to Anahata's maven repository

#!xml
   <repositories>
        <repository>
            <id>anahata</id>
            <name>Anahata Public Repo</name>
            <url>http://artifactory.anahata-it.com.au/artifactory/anahata-public/</url>
        </repository>        
   </repositories>

   <dependencies>
       <dependency>
            <groupId>com.anahata</groupId>
            <artifactId>myob-api</artifactId>
            <version>1.5.4</version>
        </dependency>
   </dependencies>

Java SE Quickstart

OAuth Log in from a standalone desktop javafx application to get access and refresh tokens and list all company files of the logged in user

#!java
JavaFXOAuthAuthenticatorApp.loginAndGetToken(new MyobPlugin("qumsp9e1b8ynw9zhbsbt53dx", "Sj3kswJqB521WmbnqG5XuBWk", "http://localhost"));                
OAuthAccessToken token = JavaFXOAuthAuthenticatorApp.ret;
CompanyFileService.findAll(token);

Retrieve all suppliers of a cloud data file. If the API detects that a token refresh is needed, allow storing the new access and refresh token

#!java
        SupplierService cfs = new SupplierService();
        cfs.setEndPointProvider(new MyobEndPointProvider() {
            @Override
            public MyobEndPoint getEndPoint() {
                OAuthAccessToken token = //read token from database;
                return new MyobEndPoint(MyobEndPoint.CLOUD_ENDPOINT + "b2c48941-7bfb-4f7c-9356-309127f15221", new DataFileCredentials(), token);
            }

            @Override
            public void oauthTokenRefreshed(MyobEndPoint locator) {
                //store access and refresh token here
            }
        });
        return cfs.findAll();

CDI provided Endpoints

The API can work with CDI (in both SE and EE environments) to provide data file url and credentials without having to configure each an MYOB service instances.

CDI based EndPoint provider supplying EndPoint (Data file locator + OAuth credentials + data file credentials). Use case of one data file and one logon for the entire application. You can Use @RequestScoped rather than @Singleton in a multi datafile, multi user scenario.

#!java
/**
 * Singleton EJB to store supply myob endpoint details and store access and refresh token whenever it gets refreshed. 
 *
 * @author pablo
 */
@ConcurrencyManagement(CONTAINER)
@Singleton
@Slf4j
@Lock(LockType.WRITE)
public class MyobEndPointProviderServiceImpl implements MyobEndPointProviderService {
    @Inject 
    @Yam
    private EntityManager em;

    @Inject 
    private DomainConfigServiceImpl dcs;

    private MyobEndPoint endPoint;

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public MyobEndPoint getEndPoint() {
        if (endPoint != null) {
            log.debug("Returning existing singleton endPoint instance {}", endPoint);
            return endPoint;
        }

        DomainConfig dc = dcs.getDomainConfigLocal();

        endPoint = new MyobEndPoint(dc.getMyobEndPointUrl());

        endPoint.getCredentials().setUser(dc.getMyobCompanyFileUser());
        endPoint.getCredentials().setPassword(dc.getMyobCompanyFilePassword());

        if (dc.getMyobKey() != null) {
            MyobPlugin mp = new MyobPlugin(dc.getMyobKey(), dc.getMyobSecret(), dc.getMyobRedirectUrl());            
            OAuthAccessToken oaat = new OAuthAccessToken(mp, dc.getMyobAccessToken(), dc.getMyobRefreshToken(), dc.getMyobAccessTokenDate(), dc.getMyobAccessTokenExpiresIn());            
            endPoint.setOauthAccessToken(oaat);
        }

        log.debug("Returning newly created singleton endPoint instance {}", endPoint);

        return endPoint;
    }

    //if the token is refreshed, we want to make sure the storage operation succeeds regardless of the transactional context
    @Override
    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void oauthTokenRefreshed(MyobEndPoint endPoint) {
        log.debug("OauthTokenRefreshed, storing on DB");
        DomainConfig dc = dcs.getDomainConfigLocal();
        dc.setMyobAccessToken(endPoint.getOauthAccessToken().getAccessToken());
        dc.setMyobRefreshToken(endPoint.getOauthAccessToken().getRefreshToken());
        dc.setMyobAccessTokenDate(endPoint.getOauthAccessToken().getCreatedOn());
        dc.setMyobAccessTokenExpiresIn(endPoint.getOauthAccessToken().getExpiresIn());
        em.merge(dc);
        em.flush();
        log.debug("Updating singleton endpoint instance");
        //update singleton instance
        getEndPoint().getOauthAccessToken().setAccessToken(endPoint.getOauthAccessToken().getAccessToken());
        getEndPoint().getOauthAccessToken().setCreatedOn(endPoint.getOauthAccessToken().getCreatedOn());
        getEndPoint().getOauthAccessToken().setExpiresIn(endPoint.getOauthAccessToken().getExpiresIn());
        getEndPoint().getOauthAccessToken().setRefreshToken(endPoint.getOauthAccessToken().getRefreshToken());
    }

}

Then on a EJB or any other CDI enabled object

#!java


/**
 * Performs persistence operations on customer such as search.
 *
 * @author pablo
 */
@Stateless
@LocalBean
public class SomeApplicationService {
    /** Myob Customer Service with CDI configured endpoint and credentials **/
    @Inject
    private CustomerService myobCustomerService;

}

Adding additional services or convenience methods to the API

While all MYOB entity classes exist in the API, only the services we have needed have been implemented. Implementing a service which has not yet been written is as simple as implementing a simple Service class and its corresponding Page object. Feel free to create new services and add a pull request.

First AccountService.java

#!java

/**
 *  Account Service
 *
 * @author pablo
 */
public class AccountService extends AbstractEntityMyobService<AccountPage, Account> {

    public AccountService() {
        super("GeneralLedger/Account", AccountPage.class, Account.class);
    }

   //Your handy methods

    public Account findByDisplayID(String displayID) {
        List<Account> accounts = super.findAll();
        for (Account account : accounts) {
            if (Objects.equal(account.getDisplayID(), displayID)) {
                return account;
            }
        }
        return null;
    }

}
And then AccountPage.java
#!java
@Data
public class AccountPage extends EntityPage<Account>{
    public List<Account> Items;
}

Updated