Javascript Post Medthod

Hi,

Can anyone help me with Javascript post method? Before I am doing a web app I am testing Get and Post methods, with Get everything is ok, but Post does not work for me and I can not see where mistake is. So I am trying to Post “StartActivity”, seems everything goes well when I do this in swagger it creates new activity in epicor, but when I try the same in postman and javascript fetch I get an error:

{

    "odata.error": {

        "code": "",

        "message": {

            "lang": "en-US",

            "value": "Unsupported Media Type"

        }

    }

}

My script looks like this:

function StartActivity(){
    let link = "https://xxx/xxx/api/v1/Erp.BO.LaborSvc/Update";            
    let h = new Headers();
    h.append('Accept', 'application/json');
    let encoded = window.btoa('User:password');
    let auth = 'Basic ' + encoded;
    h.append('Authorization', auth );            
    
    let req = new Request(link, {
        method: 'POST',
        headers: h,
        body: JSON.stringify({
            "ds": {
                "LaborHed": [
                  {
                    "Company": "SFU",
                    "EmployeeNum": "415",
                    "LaborHedSeq": 141422,
                    "PayrollDate": "2022-08-09T00:00:00",
                    "Shift": 123,
                    "ClockInDate": "2022-08-08T00:00:00",
                    "ClockInTime": 8.72,
                    "DspClockInTime": "08:43",
                    "ActualClockInTime": 8.72,
                    "ActualClockinDate": "2022-08-08T00:00:00",
                    "LunchStatus": "N",
                    "ActLunchOutTime": 0,
                    "LunchOutTime": 0,
                    "ActLunchInTime": 0,
                    "LunchInTime": 0,
                    "ClockOutTime": 0,
                    "DspClockOutTime": "",
                    "ActualClockOutTime": 0,
                    "PayHours": 0,
                    "FeedPayroll": false,
                    "TransferredToPayroll": false,
                    "LaborCollection": true,
                    "TranSet": "",
                    "ActiveTrans": true,
                    "ChkLink": "",
                    "BatchTotalHrsDisp": "",
                    "BatchHrsRemainDisp": "",
                    "BatchHrsRemainPctDisp": "",
                    "BatchSplitHrsMethod": "",
                    "BatchAssignTo": false,
                    "BatchComplete": false,
                    "BatchStartHrs": null,
                    "BatchEndHrs": null,
                    "BatchTotalHrs": 0,
                    "BatchHrsRemain": 0,
                    "BatchHrsRemainPct": 0,
                    "SysRevID": 110238777,
                    "SysRowID": "965b62cb-b6a1-4d7a-8866-cb04517c90a7",
                    "Imported": false,
                    "ImportDate": null,
                    "BatchMode": false,
                    "HCMPayHoursCalcType": "",
                    "EmpBasicShift": 123,
                    "EmpBasicSupervisorID": "472",
                    "GetNewNoHdr": false,
                    "HCMTotPayHours": 0,
                    "ImagePath": "empphoto/SFU/.bmp",
                    "LunchBreak": false,
                    "MES": false,
                    "PayrollValuesForHCM": "NON",
                    "TimeDisableDelete": false,
                    "TimeDisableUpdate": false,
                    "TotBurHrs": 0,
                    "TotLbrHrs": 0,
                    "WipPosted": false,
                    "DspPayHours": 0,
                    "FullyPosted": false,
                    "PartiallyPosted": false,
                    "HCMExistsWithStatus": false,
                    "PayrollDateNav": "2022-08-09T00:00:00",
                    "BitFlag": 0,
                    "EmployeeNumFirstName": "Justas",
                    "EmployeeNumName": "Justas Dagys",
                    "EmployeeNumLastName": "Dagys",
                    "HCMStatusStatus": "",
                    "PRSystHCMEnabled": false,
                    "ShiftDescription": "00:00 to 00:00",
                    "RowMod": ""
                  }
                ],
                "LaborDtl": [
                  {
                    "Company": "SFU",
                    "EmployeeNum": "415",
                    "LaborHedSeq": 141422,
                    "LaborDtlSeq": 101707,
                    "LaborType": "P",
                    "LaborTypePseudo": "P",
                    "ReWork": false,
                    "ReworkReasonCode": "",
                    "JobNum": "FRM015162",
                    "AssemblySeq": 0,
                    "OprSeq": 30,
                    "JCDept": "PCL",
                    "ResourceGrpID": "90",
                    "OpCode": "PC D",
                    "LaborHrs": 0,
                    "BurdenHrs": 0,
                    "LaborQty": 0,
                    "ScrapQty": 0,
                    "ScrapReasonCode": "",
                    "SetupPctComplete": 0,
                    "Complete": false,
                    "IndirectCode": "",
                    "LaborNote": "",
                    "ExpenseCode": "ADM",
                    "LaborCollection": true,
                    "AppliedToSchedule": false,
                    "ClockInMInute": 36172125,
                    "ClockOutMinute": 36173565,
                    "ClockInDate": "2022-08-08T00:00:00",
                    "ClockinTime": 12.75,
                    "ClockOutTime": 24,
                    "ActiveTrans": true,
                    "OverRidePayRate": 0,
                    "LaborRate": 17,
                    "BurdenRate": 151.45,
                    "DspClockInTime": "12:45",
                    "DspClockOutTime": "00:00",
                    "ResourceID": "9001",
                    "OpComplete": false,
                    "EarnedHrs": 0,
                    "AddedOper": false,
                    "PayrollDate": "2022-08-09T00:00:00",
                    "PostedToGL": false,
                    "FiscalYear": 0,
                    "FiscalPeriod": 0,
                    "JournalNum": 0,
                    "GLTrans": true,
                    "JournalCode": "",
                    "InspectionPending": false,
                    "CallNum": 0,
                    "CallLine": 0,
                    "ServNum": 0,
                    "ServCode": "",
                    "ResReasonCode": "",
                    "WipPosted": false,
                    "DiscrepQty": 0,
                    "DiscrpRsnCode": "",
                    "ParentLaborDtlSeq": 0,
                    "LaborEntryMethod": "T",
                    "FiscalYearSuffix": "",
                    "FiscalCalendarID": "",
                    "BFLaborReq": false,
                    "ABTUID": "",
                    "ProjectID": "",
                    "PhaseID": "",
                    "RoleCd": "",
                    "TimeTypCd": "",
                    "PBInvNum": 0,
                    "PMUID": 0,
                    "TaskSetID": "",
                    "ApprovedDate": null,
                    "ClaimRef": "",
                    "QuickEntryCode": "",
                    "TimeStatus": "",
                    "CreatedBy": "",
                    "CreateDate": null,
                    "CreateTime": 0,
                    "ChangedBy": "",
                    "ChangeDate": null,
                    "ChangeTime": 0,
                    "ActiveTaskID": "",
                    "LastTaskID": "",
                    "CreatedViaTEWeekView": false,
                    "CurrentWFStageID": "",
                    "WFGroupID": "",
                    "WFComplete": false,
                    "ApprovalRequired": false,
                    "SubmittedBy": "",
                    "PBRateFrom": "",
                    "PBCurrencyCode": "",
                    "PBHours": 0,
                    "PBChargeRate": 0,
                    "PBChargeAmt": 0,
                    "DocPBChargeRate": 0,
                    "Rpt1PBChargeRate": 0,
                    "Rpt2PBChargeRate": 0,
                    "Rpt3PBChargeRate": 0,
                    "DocPBChargeAmt": 0,
                    "Rpt1PBChargeAmt": 0,
                    "Rpt2PBChargeAmt": 0,
                    "Rpt3PBChargeAmt": 0,
                    "Shift": 1,
                    "ActID": 0,
                    "DtailID": 0,
                    "ProjProcessed": false,
                    "AsOfDate": null,
                    "AsOfSeq": 0,
                    "JDFInputFiles": "",
                    "JDFNumberOfPages": "",
                    "BatchWasSaved": "",
                    "AssignToBatch": false,
                    "BatchComplete": false,
                    "BatchRequestMove": false,
                    "BatchPrint": false,
                    "BatchLaborHrs": 0,
                    "BatchPctOfTotHrs": 0,
                    "BatchQty": 0,
                    "BatchTotalExpectedHrs": 0,
                    "JDFOpCompleted": "",
                    "SysRevID": 0,
                    "SysRowID": "00000000-0000-0000-0000-000000000000",
                    "Downtime": false,
                    "RefJobNum": "",
                    "RefAssemblySeq": 0,
                    "RefOprSeq": 0,
                    "Imported": false,
                    "ImportDate": null,
                    "TimeAutoSubmit": false,
                    "BatchMode": false,
                    "BillServiceRate": 0,
                    "HCMPayHours": 0,
                    "EpicorFSA": false,
                    "DiscrepAttributeSetID": 0,
                    "LaborAttributeSetID": 0,
                    "ScrapAttributeSetID": 0,
                    "AllowDirLbr": true,
                    "ApprovalPhaseDesc": "",
                    "ApprovalPhaseID": "",
                    "ApprovalProjectDesc": "",
                    "ApprovalProjectID": "",
                    "ApprovedBy": "",
                    "ApprvrHasOpenTask": false,
                    "BaseCurrCodeDesc": "",
                    "BurdenCost": 0,
                    "CallCode": "",
                    "CapabilityDescription": "",
                    "CapabilityID": "",
                    "ChargeRate": 0,
                    "ChargeRateSRC": "",
                    "ChgRateCurrDesc": "",
                    "CompleteFlag": false,
                    "ContractCode": "",
                    "ContractNum": 0,
                    "DiscrepUOM": "vnt",
                    "DisLaborType": false,
                    "DisplayJob": "FRM015162",
                    "DisPrjRoleCd": true,
                    "DisTimeTypCd": true,
                    "DowntimeTotal": 0,
                    "DspChangeTime": "",
                    "DspCreateTime": "",
                    "DspTotHours": "",
                    "DtClockIn": null,
                    "DtClockOut": null,
                    "EfficiencyPercentage": 0,
                    "EmployeeName": "",
                    "EnableComplete": false,
                    "EnableCopy": false,
                    "EnableDiscrepQty": true,
                    "EnableInspection": false,
                    "EnableLaborQty": true,
                    "EnableNextOprSeq": false,
                    "EnablePrintTagsList": false,
                    "EnableRecall": false,
                    "EnableRecallAprv": false,
                    "EnableRequestMove": false,
                    "EnableResourceGrpID": true,
                    "EnableScrapQty": true,
                    "EnableSN": false,
                    "EnableSubmit": false,
                    "EndActivity": false,
                    "EnteredOnCurPlant": false,
                    "FSAAction": "",
                    "FSACallCode": "",
                    "FSAContractCode": "",
                    "FSAContractNum": 0,
                    "FSAEmpID": "",
                    "FSAEquipmentInstallID": 0,
                    "FSAEquipmentPartNum": "",
                    "FSAServiceOrderNum": 0,
                    "FSAServiceOrderResourceNum": 0,
                    "FSAWarrantyCode": "",
                    "FSComplete": false,
                    "GLTranAmt": 0,
                    "GLTranDate": null,
                    "HasAccessToRow": true,
                    "HasComments": false,
                    "HH": false,
                    "IntExternalKey": "",
                    "ISFixHourAndQtyOnly": false,
                    "JCSystReworkReasons": true,
                    "JCSystScrapReasons": true,
                    "JobOperComplete": false,
                    "JobType": "Manufacture",
                    "JobTypeCode": "MFG",
                    "LaborCost": 0,
                    "LaborUOM": "vnt",
                    "LbrDay": "",
                    "LbrMonth": "",
                    "LbrWeek": "",
                    "MES": true,
                    "MultipleEmployeesText": "1 Employee(s) are already working on this operation",
                    "NewDifDateFlag": 0,
                    "NewPrjRoleCd": "",
                    "NewRoleCdDesc": "",
                    "NextAssemblySeq": 0,
                    "NextOperDesc": "",
                    "NextOprSeq": 0,
                    "NextResourceDesc": "",
                    "NonConfProcessed": false,
                    "NotSubmitted": false,
                    "OkToChangeResourceGrpID": false,
                    "PartDescription": "",
                    "PartNum": "SFF01097",
                    "PBAllowModify": false,
                    "PendingApprovalBy": "",
                    "PhaseJobNum": "",
                    "PhaseOprSeq": 0,
                    "PrintNCTag": false,
                    "PrjUsedTran": "",
                    "ProdDesc": "",
                    "ProjPhaseID": "",
                    "RequestMove": false,
                    "ResourceDesc": "",
                    "RoleCdDisplayAll": false,
                    "ScrapUOM": "vnt",
                    "SentFromMES": false,
                    "StartActivity": true,
                    "TimeDisableDelete": false,
                    "TimeDisableUpdate": false,
                    "TreeNodeImageName": "",
                    "UnapprovedFirstArt": false,
                    "WarrantyCode": "",
                    "WeekDisplayText": "",
                    "PCID": "",
                    "EnablePCID": false,
                    "OutputBin": "",
                    "OutputWarehouse": "",
                    "EnableLot": false,
                    "LotNum": "",
                    "PrintPCIDContents": false,
                    "HasAttachments": false,
                    "AttrClassID": "",
                    "DiscrepAttributeSetDescription": "",
                    "DiscrepAttributeSetShortDescription": "",
                    "ScrapAttributeSetDescription": "",
                    "ScrapAttributeSetShortDescription": "",
                    "LaborAttributeSetDescription": "",
                    "LaborAttributeSetShortDescription": "",
                    "DisableRecallAndDelete": false,
                    "RoleCdList": "",
                    "RowSelected": false,
                    "AppointmentStart": null,
                    "AppointmentEnd": null,
                    "AppointmentTitle": "",
                    "TemplateID": "",
                    "BitFlag": 0,
                    "DiscrpRsnDescription": "",
                    "EmpBasicLastName": "Dagys",
                    "EmpBasicFirstName": "Justas",
                    "EmpBasicName": "Justas Dagys",
                    "ExpenseCodeDescription": "ADM",
                    "HCMIntregationHCMEnabled": false,
                    "HCMStatusStatus": "",
                    "IndirectDescription": "",
                    "JCDeptDescription": "Dažymas / Powder coating Dep.",
                    "JobAsmblPartNum": "SFF01097",
                    "JobAsmblDescription": "LOW VOLTAGE MOUTING PL, FUSE",
                    "MachineDescription": "Dažymas / PCL 1",
                    "OpCodeOpDesc": "DAŽYMAS",
                    "OpDescOpDesc": "DAŽYMAS",
                    "PayMethodType": 0,
                    "PayMethodSummarizePerCustomer": false,
                    "PayMethodName": "",
                    "PhaseIDDescription": "",
                    "ProjectDescription": "",
                    "ResourceGrpDescription": "Dažymas / Powder coating",
                    "ResReasonDescription": "",
                    "ReWorkReasonDescription": "",
                    "RoleCdRoleDescription": "",
                    "ScrapReasonDescription": "",
                    "ShiftDescription": "",
                    "TimeTypCdDescription": "",
                    "RowMod": "A"
                  }
                ]
            }
          })
        
    })

    
                    
    fetch(req)
    .then(res=>res.json())
     
    
}

Can you show the postman settings for the failed call?

Finally found. :partying_face:

h.append(‘Accept’, ‘application/json’); this has to be like this h.append(‘Content-Type’, ‘application/json’);

And the postman gave the same error because in Raw I picked JavaScript instead Json

1 Like

un-related are you running this client side javascript with a hardcoded ‘username:password’ as part of the script?

1 Like

I know that is awful, this script will be used only in local computer in browser. At the moment I have no idea how to do this that it would not be harcoded.

Dare I ask what you are doing? If its a web app I’m assuming someone is going to use it yeah? in the VERY least I would put two text fields on the page and then get their content using docoument get byid so that at least the js file itself doesn’t have the hard coded passwords.

<input type="text" id="inpUserName"/>
<input type="password" id="inpPassword"/>

Then in your script do

var userName = document.getElementByID('inpUserName').value;
var pwd = = document.getElementByID('inpPassword').value;

use those two variables inside our btoa at least this way someone has to physically run your index.html and type in those values before the request works…

It is still awful, but just less awful. If you explain what you are trying to do and why does it need to be a javascript / web app since its local we might be able to provide better feedback.

2 Likes

Ok this should be like a work station attached to the machine where users would be able to start activity.
Purpose to use drag and drop functionality, script would display possible jobs which you can drag to

container by saying that now this job are in process on this machine in another container active employees would be shown, by this every employee who wants to participate in this job would be able to move their name with a finger on to that job and they would start activity.

1 Like

Yeah I would definitely recommend you write this using a more secure mechanism than hard coding some passwords into your file.

you should provide a method to login / log out and one that doesn’t store the plain text username and password. You should also ensure the calls you are making are Scope Controlled on the Epicor side via an APIKey

Just because this app is “internal” doesn’t mean it isn’t a security theat. If a threat actor gets into your file system they can simply look at your hardcoded username/ password here to gain access to your ERP system.

1 Like

Do you have any links or anything to a mechanism you think is most straightforward for someone like Justas? It may not be the most secure method, but is generally accepted?

What is the most secure way to provide a login? Any links to that?

There is a lot of very specific things that can be done. Unfortunately there isn’t a silver bullet, for one there are 101 frameworks out there all which operate differently.

The general idea is don’t store secrets in the client (ever) and protect your end points with API keys and Scope

In this case above I would recommend having an app with at least 2 components one where the users can provide their unsername and password this is then passed on to epicor via a REST request to Generate Token (JWT) this token then can be retrieved from the request and used in subsequent requests without having to store the username and password.

Then in the second page he can use this token to make the appropriate requests, the token has a TTL a time to live usually an hour so every hour or so users will have to re-authenticate, (or a mechanism can be established such that the token is automatically refreshed while the user is active.

2 Likes

Tokens are good point. But I have question about access scope api, so now we can directly access bo without api-key, I can create an access scope for this bo and include api- key in script headers, but if some one would access script directly and remove it from headers, then bo will be accessable, yes?
So it is more helpful when the app are built like in C# and compliled probably.

that’s only because you are using API V1, you should use API V2 which ALWAYS requires APIKeys and scope.

1 Like

This is my humble opinion:

Who are we kidding? Humble opinion my :peach:
:rofl:

Yes, this requires more setup but I would argue that this architecture will be more secure, simplify client-code, and make upgrades smoother. @olga would call this a BFF: a backend for frontend design. It’s an extra layer that mediates between different front-ends. It would look like this:

  • Design an API for your front end. The client no-longer needs to know all of the Epicor implementation details. The API will have its own authentication. I recommend Azure AD if you’re already using it. If your Kinetic is in the cloud, then you can easily deploy the API in the cloud and get the security and rate limiting available in Azure too.

  • Use Azure Key Vault to store the API keys. Once a person authenticates to Azure AD, the backend can retrieve the API-Key for you. So no security details in your client. Also, you can use advanced features of Azure AD to enforce MFA or do conditional access.

  • Write an Epicor Function to do the actual Epicor transaction and have your API call Epicor. Epicor Functions always uses REST v2.

  • Use Postman or other REST client to test the Epicor Function library and another to test the API.

  • For those who adopt this pattern on 10.2.500 (or later for Function capability), you can upgrade to Kinetic with little or no changes in your clients or integrations.

Those are my thoughts, but honestly always interested in feedback from others.

2 Likes

I have a stupid question. Can you have it so the API scope only allows it to access a few specific Epicor Functions you’ve made, or would it need access to everything called inside that function?

1 Like

Looks like individual functions within libraries:

image

I assume you mean all or nothing for Library?

2 Likes

I just posted this Angular Template for a Basic Epicor Web App Using Rest I would suggest you follow something like this to make any apps that will be used by someone other than you on your computer.

The app above uses the Epicor Token Endpoint to authenticate and never holds any secrets other than the JWT which is signed (can’t be tampered with) and time limited.

It also uses an API Key which can be scoped down to the service / end points that you want to expose.

4 Likes