epicor-rest-node
TypeScript icon, indicating that this package has built-in type declarations

1.1.16 • Public • Published

Epicor Rest Helper for Node

This library helps make Epicor calls from a Node application. This library is not official and has no direct relationship with Epicor (c). It is merely a helper library maintained by the community.

Installation

npm i --save epicor-rest-node

Usage

Setup

import { EpicorRestService, EpicorRestVersion } from 'epicor-rest-node';
import { EpicorLicenseType } from 'epicor-rest-node/dist/models/EpicorLicenseType';
  // For single instance creation
  let EpicorRest = new EpicorRestService();

  // or injected into another class/service such as a controller
  constructor(private readonly epicorSvc: EpicorService) {}

  // Instance properties required to function
  EpicorRest.AppPoolHost = 'subdomain.domain.tld';
  EpicorRest.AppPoolInstance = 'Epicor10Instance';
  EpicorRest.UserName = 'MyEpicorUserName';
  EpicorRest.Password = 'MyEpicorPassword';
  EpicorRest.APIKey = 'xxxxxxxxxxxxxxxxxxxxxxxxx'; //Needed for V2
  EpicorRest.Company = 'EPIC01';
  EpicorRest.EpicorRestVersion = EpicorRestVersion.V2; //Defaults to V2
  EpicorRest.License = EpicorLicenseType.WebService; //Defaults to Default
Handling Instance Scope

@Injectable({ scope: Scope.REQUEST }) tells Nest to treat your service class as a provider with request scope. In practical terms:

  1. @Injectable(): Marks the class so Nest can manage and inject it wherever needed (dependency injection).
  2. scope: Scope.REQUEST: Tells Nest to create a new instance of this class for each incoming request, rather than reusing a single global instance. This is useful if each request needs its own state or dependencies. (NOTE: This will also consume additional licenses in Epicor)
import { EpicorRestService } from 'epicor-rest-node';

// Adding REQUEST scope will force a new instance per request made vs a singleton
@Injectable({scope: Scope.REQUEST})
export class EpicorService extends EpicorRestService implements OnModuleInit {
  public Plant: string = "MfgSys";

  /**
   * Constructor
   */
  constructor(
    private readonly config: ConfigService
  ) {
    super();
    this.AppPoolHost = 'subdomain.domain.tld';
    this.AppPoolInstance = 'Epicor10Instance';
    this.UserName = 'MyEpicorUserName';
    this.Password = 'MyEpicorPassword';
    this.APIKey = 'xxxxxxxxxxxxxxxxxxxxxxxxx'; //Needed for V2
    this.Company = 'EPIC01';
    this.EpicorRestVersion = EpicorRestVersion.V2; //Defaults to V2
    this.License = EpicorLicenseType.WebService; //Defaults to Default

    // TODO: Do we need to implement timezone offset
    this.CallSettings = new CallSettings(this.Company, this.Plant, '', '', '');

    console.log('My Custom EpicorService Constructor');
  }
  .
  .
  .
    /**
    * Switch Employee ID
    * @param empID
    */
    public async switchEmployee(empID: string) {
      let switchRes = await this.BoPost("Ice.Lib.SessionModSvc", "SetEmployee", { employeeID: empID });
      return switchRes;
    }
  .
  .
  .
}

Call BO Methods

let params = new Map<string,string>();
params.set('$filter','ABCCode1 eq \'A\'');

EpicorRest.BoGet('Erp.BO.ABCCodeSvc','ABCCodes',params)?.then(res => {
    console.log(res);}).catch(err => {
    console.log(err);
  });

EpicorRest.BoPost('Erp.BO.ABCCodeSvc','ABCCodes',data)?.then(res => {
    console.log(res);}).catch(err => {
    console.log(err);
  });

// Patch and Delete are also available

Call BAQ

let params = new Map<string,string>();
params.set('$top','13');

EpicorRest.BaqGet('zCustomer01', params)?.then(res => {
    console.log(res);
  }).catch(err => {
    console.log(err);
  });

//BAQ Patch is also available

Call Epicor Function

let smsSend = 
  {
    ToPhone:'123456789',
    ToMsg:'Zup from Node'
  };
EpicorRest.EfxPost('FacilityPaging','SendSMS',smsSend)?.then(res => {
    console.log(res);
  }).catch(err => {
    console.log(err);
  });

Advanced Usage

Epicor Session

An Epicor session can be established at any point by invoking EpicorRest.Createsession() and make sure to kill the session when you are done.

  EpicorRest.Createsession().then((success) => {
    // Any calls made in here will use the above created session
    let params = new Map<string,string>();
    params.set('$filter','ABCCode1 eq \'A\'');

    EpicorRest.BoGet('Erp.BO.ABCCodeSvc','ABCCodes',params)?.then(res => {
      console.log(res);}).catch(err => {
      console.log(err);
    }).finally(() => {
      EpicorRest.DestroySession();
    });
  }).catch((ex) => {
    console.log(ex);
  });

An Epicor session can be killed manually by invoking EpicorRest.DestroySession() this needs to be done after the last call to the BO/BAQ/EFX etc.

Epicor Call Context

Sending Call Context To Node

Managing call context as an object can be done by using the EpicorRest CallContext models.

Generate a header with the call context values you want in your client application and send it in the contextheader header of your request.

  {
    "Context":{
      "BpmData":[
        {
          "Character01":"FOO",
          "Character02":"BAR",
          "Checkbox01":true,
          "Date01":"2024-12-27"
        }
      ]
    }
  }
Handling Request Call Context

Below is an example controller endpoint that grabs the contextheader from the request headers and sends it to our EpicorService that implements the EpicorRestNode module. It also then takes the call context and sends it back to our client that made the request.

  /**
 * Post EFX Data
 */
  @Post('PostEFX/:library/:method')
  async postEfx(
    @Param('company') company: string,
    @Param('library') library: string,
    @Param('method') method: string,
    @Body() body: Record<string, any>, // Capture the entire JSON body
    @Req() req,
    @Res({ passthrough: true }) res: any, // passthrough is important to allow us to send the context headers back but allow interceptors to still run on our 'data' return if we need to
  ) {
    // Pass the body directly as params
    const { data, context } = await this.epicorSvc.callEFX(company, library, method, body, req.headers['contextheader']);

    // Set the `callcontext` in the response headers to our client
    res.setHeader('contextheader', JSON.stringify(context) || '');

    // Send response
    return data;
  }

In our actual service we send the headers to our EpicorRestNode module in the method signature.

  import { BpmData, CallContext, Client, Context } from 'epicor-rest-node/dist/models/CallContext';

  public async callEFX(user: any, library: string, functionName: string, params: any, callContext: string | undefined = undefined): Promise<any> {
    let efxData = undefined;
    let respCallContext = undefined

    let session = await EpicorRest.Createsession().then((success) => {
      // Convert the string passed in to an object of CallContext
      const reqCallContext = new CallContext(JSON.parse(callContext).Context);

      // Modify the call context as you need      
      reqCallContext.Context.BpmData[0].Character01 = "MyCustomAppSentThis";
  
      // Call our method in the EpicorRestNode module passing CallContext as a param
      efxData = await this.EfxPost(library, functionName, params, false, reqCallContext).then((res) => {
        respCallContext = new CallContext(JSON.parse(res.headers['contextheader']).Context); // Capture the callcontext from response headers
        return res.data;}).catch(err => {
        console.log(err);
      }).finally(() => {
        EpicorRest.DestroySession();
      });
    }).catch((ex) => {
      console.log(ex);
    });

    // Here we return our response data and the call context as two seperate objects to our controller above
    return { data: efxData, context: respCallContext };
  }

Additionally if you wanted to you could create an interface for that return data so in your controller you can get the type cast autocomplete goodness

export interface EpicorResponse {
  data: any;
  context: CallContext;
}

// In our service we switch our promise from 'any'
public async callEFX(user: any, library: string, functionName: string, params: any, callContext: string | undefined = undefined): Promise<any> {

// to 'EpicorResponse'
public async callEFX(user: any, library: string, functionName: string, params: any, callContext: string | undefined = undefined): Promise<EpicorResponse> {

Package Sidebar

Install

npm i epicor-rest-node

Weekly Downloads

18

Version

1.1.16

License

MIT

Unpacked Size

39.8 kB

Total Files

13

Last publish

Collaborators

  • josecgomez
  • jgiese06