So far, this is working great! I have one small issue where I want to pull data from the timeclock, where there are no records in Epicor. For example, our Drivers punch in and out, but don’t use Epicor. My BAQ that pulls the data from the API is based on the JCDept and a filter. But the JCDept for drivers, doesn’t exist in Epicor. I have set the two departments that are not in Epicor to 100, and 101. I think I need to switch around my base query to pull based on just the list of JCDepts that I give, but not have it be restricted to only the JCDepts in Epicor. Basically, here is a list of JCDeptIDs. Get the internal Epicor data for them, and the timeclock data. If one or the other doesn’t exist then just show a blank or 0.
Base UBAQ:
select
[DeptEff].[LaborHed_Company] as [LaborHed_Company],
[DeptEff].[JCDept1_JCDept] as [JCDept1_JCDept],
[DeptEff].[JCDept1_Description] as [JCDept1_Description],
(EarnedHours.Calculated_ProdEH) as [Calculated_DayEH],
(DeptEff.Calculated_LaborHours) as [Calculated_DayLab],
(DayEH/ DayLab) as [Calculated_DayProd],
(0) as [Calculated_TCHrs],
(@EndDate) as [Calculated_myDate],
(0) as [Calculated_pulled]
from (select
[LaborHed].[Company] as [LaborHed_Company],
[JCDept1].[Description] as [JCDept1_Description],
(sum(LaborDtl1.LaborHrs)) as [Calculated_LaborHours],
[JCDept1].[JCDept] as [JCDept1_JCDept]
from Erp.LaborDtl as LaborDtl1
inner join Erp.LaborHed as LaborHed on
LaborHed.Company = LaborDtl1.Company
and LaborHed.LaborHedSeq = LaborDtl1.LaborHedSeq
inner join Erp.EmpBasic as EmpBasic on
EmpBasic.Company = LaborHed.Company
and EmpBasic.EmpID = LaborHed.EmployeeNum
inner join Erp.JCDept as JCDept1 on
LaborDtl1.Company = JCDept1.Company
and LaborDtl1.JCDept = JCDept1.JCDept
where (LaborDtl1.JCDept in ('11', '12', '15', '16', '2', '3', '4', '5', '8', '9', '100', '101') and LaborDtl1.PayrollDate >= @StartDate and LaborDtl1.PayrollDate <= @EndDate)
group by [LaborHed].[Company],
[JCDept1].[Description],
[JCDept1].[JCDept]) as DeptEff
inner join (select
[JCDept].[Description] as [JCDept_Description],
(sum(LaborDtl.EarnedHrs)) as [Calculated_ProdEH]
from Erp.LaborDtl as LaborDtl
inner join Erp.JCDept as JCDept on
LaborDtl.Company = JCDept.Company
and LaborDtl.JCDept = JCDept.JCDept
where (LaborDtl.PayrollDate >= @StartDate and LaborDtl.PayrollDate <= @EndDate)
group by [JCDept].[Description]) as EarnedHours on
DeptEff.JCDept1_Description = EarnedHours.JCDept_Description
order by DeptEff.JCDept1_JCDept Desc
Here is the GetList Method, with my custom Directive GetHours:
And here are my two functions inside the library:
GetDeptKey(in DeptID, out DeptKey):
//use the epicor dept id code to lookup the dept key from asure
Dictionary<string, string> departmentKeys = new Dictionary<string, string>
{
{"9:Quality Control", "791866ff-f69d-4217-b744-3270a06ce846"},
{"11:Sheet Metal", "9736c126-e903-42fc-b943-6518b62bbec3"},
{"10:Shipping", "5edc6acb-176a-4f8a-b7b9-6974cb8e9eb4"},
{"15:Horizontal", "8157cce9-133e-4f0e-917c-b17857e92512"},
{"8:Burr Bench", "00916604-403f-433a-84eb-c9c9b93dbd76"},
{"100:Maintenance", "8d94bf71-6734-4990-96c7-da4f41cea9d9"},
{"4:N.C. Mill", "ffdd73c8-e840-4641-9b9c-e49901c65b33"},
{"101:Drivers", "7e3000a3-6315-4527-8fab-efad773c0ae5"},
{"2:Lathe Department", "04e6a140-12f1-4a92-aab5-f625737a5cc2"},
{"5:Bridgeport", "9c230560-724e-40e1-8ebd-fa970b9eb00d"}
};
foreach (var department in departmentKeys)
{
var deptIDName = department.Key;
var deptKey = department.Value;
// Split the input data based on ":"
string[] parts = deptIDName.Split(':');
// Extract department code and name
var deptCode = parts[0];
if (DeptID == deptCode)
{
DeptKey = deptKey;
}
}
GetDeptHrs(in deptKey, in myDate, out deptHours):
try
{
// Base URL for the API
var URL = "MYURL";
// Initialize RestClient
var client = new RestClient(URL);
// Parse myDate to match the expected format for the API call
if (!DateTime.TryParseExact(myDate.ToString(), "M/d/yyyy h:mm:ss tt", null, System.Globalization.DateTimeStyles.None, out DateTime dateTimeValue))
{
// Debug message for invalid date format
myDebugMsg += "[ERROR] Invalid date format";
return; // Exit the try block as date parsing failed
}
string formattedDate = dateTimeValue.ToString("yyyy-MM-dd");
// Debug message for formatted date
myDebugMsg += "Formatted Date: " + formattedDate + " | ";
// Construct the API request URL
var myRequest = "webapi/timecards/level/" + deptKey + "/payrolldata/" + formattedDate;
myDebugMsg += myRequest;
// Create a RestRequest with the constructed URL and GET method
var request = new RestRequest(myRequest, Method.GET);
// Add authorization header
request.AddHeader("Authorization", "Basic MYAUTHSTRING");
// Execute the request
IRestResponse myIResponse = client.Execute(request);
// Check if request was successful
if (myIResponse.StatusCode != System.Net.HttpStatusCode.OK)
{
// Debug message for failed API request
myDebugMsg += "[ERROR] API request failed: " + myIResponse.ErrorMessage + " | ";
return; // Exit the try block as API request failed
}
// Extract response content
string responseData = myIResponse.Content;
// Debug message for successful API response
myDebugMsg += "API Response: " + responseData + " | ";
// Parse the response data into a JSON array
JArray jsonData;
try
{
jsonData = JArray.Parse(responseData);
}
catch (Newtonsoft.Json.JsonReaderException ex)
{
// Debug message for JSON parsing error
myDebugMsg += "[ERROR] JSON parsing error: " + ex.Message + " | ";
return; // Exit the try block as JSON parsing failed
}
// Calculate the total hours for selected PayTypeIDs
int totalMinutes = 0;
List<string> excludedPayTypeIDs = new List<string> { "JURY", "HOL", "BER", "SICK/VACA" };
foreach (JObject record in jsonData)
{
// Extract report date and hours
string reportDate = DateTime.Parse(((string)record["ReportDate"]).Split('T')[0]).ToString("yyyy-MM-dd");
if (reportDate == formattedDate)
{
string payTypeId = record["PayTypeId"].ToString();
int minutes = Convert.ToInt32(record["Minutes"]);
if (!excludedPayTypeIDs.Contains(payTypeId))
{
totalMinutes += minutes;
}
else
{
totalMinutes -= minutes;
}
}
}
// Calculate department hours
deptHrs = ((decimal)totalMinutes / 60);
}
catch (Exception ex)
{
// Debug message for other exceptions
myDebugMsg += "[ERROR] Exception: " + ex.Message + " | ";
}
How can I base my initial UBAQ on the dept IDs that I care about?
Does this make sense? I know it is a deep rabbit hole… Thanks for taking the time to look!
Nate