private void btnUpdateJobCost_Click(object sender, EventArgs e) { SysconCommon.Common.Environment.Connections.SetOLEDBFreeTableDirectory(txtDataDir.Text); var validjobtypes_delim = Env.GetConfigVar<string>("tmtypes", "", true); var validjobtypes_strs = validjobtypes_delim.Split(','); var validjobtypes = validjobtypes_delim.Trim() == "" ? new long[] { } : validjobtypes_strs.Select(i => Convert.ToInt64(i)); using (var con = SysconCommon.Common.Environment.Connections.GetOLEDBConnection()) { long[] jobs = null; if (this.radioShowTMJobs.Checked) { using (var jobtyps = con.GetTempDBF()) { con.ExecuteNonQuery("create table {0} (jobtyp n(3, 0))", jobtyps); foreach (var jt in validjobtypes) { con.ExecuteNonQuery("insert into {0} (jobtyp) values ({1})", jobtyps, jt); } jobs = (from x in con.GetDataTable("Jobnums", "select actrec.recnum from actrec join {0} jobtypes on actrec.jobtyp = jobtypes.jobtyp", jobtyps).Rows select Convert.ToInt64(x["recnum"])).ToArray(); } } var job_selector = new MultiJobSelector(jobs); if (!(job_selector.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)) { var jobnums = job_selector.SelectedJobNumbers.ToArray(); JobCostDbHelper jobCostDB = new JobCostDbHelper(); if (jobnums.Length > 0) { long phaseNum = 0; int taxPartClassId = 0; int costCode = 0; try { //Based on the other parameters selected, run the Option 1 or Option 2. // OPTION 1 if (this.radScanJobForTax.Checked) { int acctPeriod = Convert.ToInt32(cboAcctPeriod.SelectedItem); int costCodeTax = 0; FillCostCodeForTaxInfo(out costCodeTax); FillTaxPartInfo(out taxPartClassId); using (var progress = new ProgressDialog((4 * jobnums.Length) + 2)) { progress.Tick(); progress.Text = "Starting scanning job costs for tax liabilities"; progress.Show(); foreach (long jobNum in jobnums) { // This routine scans job costs for tax liabilities jobCostDB.ScanForTaxLiability(dteStartDate.Value, dteEndDate.Value, jobNum, phaseNum, taxPartClassId, acctPeriod, costCodeTax, progress); } progress.Tick(); progress.Text = "Finished scanning job costs for tax liabilities"; } //MessageBox.Show("Finished scanning jobs for tax liabilities"); } // OPTION 2 if (this.radCombineForBilling.Checked) { FillCostCodeInfo(out costCode); using (var progress = new ProgressDialog((10 * jobnums.Length) + 2)) { progress.Tick(); progress.Text = "Starting job cost consolidation"; progress.Show(); foreach (long jobNum in jobnums) { // The next two procedures are run together to create billable cost records that // are combined from distinct job cost records by cost type. jobCostDB.ConsolidateJobCost(dteStartDate.Value, dteEndDate.Value, jobNum, phaseNum, costCode, progress); jobCostDB.UpdateTMTJobCost(dteStartDate.Value, dteEndDate.Value, jobNum, phaseNum, progress); } progress.Tick(); progress.Text = "Finished job cost consolidation"; } //MessageBox.Show("Finished consolidating job costs"); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } else { MessageBox.Show("No jobs selected.", "Error", MessageBoxButtons.OK); } } } }
/// <summary> /// This routine scans all job costs that have not been billed, and match the /// job number and phase as passed by the user. If there has been no tax liability /// accrued on the invoice from which this job cost originated, we create a job /// cost record. /// </summary> /// <param name="startDate"></param> /// <param name="endDate"></param> /// <param name="jobNumber"></param> /// <param name="jobPhase"></param> /// <param name="taxPartClassId"></param> /// <param name="acctPeriod">Accounting period.</param> public void ScanForTaxLiability(DateTime startDate, DateTime endDate, long jobNumber, long jobPhase, int taxPartClassId, int acctPeriod, int costCode, ProgressDialog progress) { //This part classification indicates which parts are considered tax parts int taxPartClass = taxPartClassId; double[] taxRates = new double[9]; Env.Log("Started processing for tax liability."); using (var con = SysconCommon.Common.Environment.Connections.GetOLEDBConnection()) { using ( Env.TempDBFPointer ActiveTaxParts = con.GetTempDBF(), ActiveJobCosts = con.GetTempDBF(), ActiveJobCostsTmp = con.GetTempDBF(), ActiveAPLines = con.GetTempDBF(), TaxJobCosts = con.GetTempDBF(), TaxTemp = con.GetTempDBF() ) { //Setting to zero. not needed for now. jobPhase = 0; //Get the data set version decimal dataSetVersion = SMBHelper.GetDataSetVersion(); int curFiscalYear = 0; if(dataSetVersion == -1) { //WAIT 'Invalid data directory' window return; } //Get the current fiscal year if required if(dataSetVersion >= 19) { curFiscalYear = SMBHelper.GetDataSetGLInfo("CURRENTFISCALYEAR"); } progress.Tick(); progress.Text = string.Format("Scanning job# {0}", jobNumber); //Get the tax rate details int taxCode = con.GetScalar<int>("SELECT slstax from actrec where recnum = {0}", jobNumber); string taxDetail = con.GetScalar<string>("Select ntetxt from taxdst where recnum = {0}", taxCode); FillTaxRates(ref taxRates, taxDetail); //Get the list of active tax rate parts for reference int fldCount = con.ExecuteNonQuery("SELECT recnum, prtnme, prtunt, csttyp, prtcls, prtcst FROM tkfprt WHERE prtcls = {0} " + "INTO Table {1} ORDER BY recnum", taxPartClass, ActiveTaxParts); //Get list of active job cost records to be billed //TODO - if JobNumber = zero, scan all jobs and phases // if JobPhase = zero, scan all phases for the jobs fldCount = con.ExecuteNonQuery("SELECT * FROM jobcst " + "WHERE jobnum = {0} " + "AND phsnum = {1} " + "AND status = 1 AND bllsts = 1 AND jobcst.trndte >= {2} AND jobcst.trndte <= {3} " + "INTO Table {4}", jobNumber, jobPhase, startDate.ToFoxproDate(), endDate.ToFoxproDate(), ActiveJobCosts); //Identify for each active job cost record if a tax burden has been applied in the //entry of the originating transactions. For now, that is only AP entries //Get the list of AP invoices associated with the job costs //1.0.8 - TaxTrnNum should not be truncated at this point. fldCount = con.ExecuteNonQuery("SELECT ajc.*, NVL(a.recnum, 00000000) as aprecnum, NVL(a.invnum, SPACE(15)) as apinvnum, 000 as taxprtcnt, " + "trnnum as TaxTrnNum, 000 as taxAccCnt " + "FROM {0} ajc LEFT JOIN acpinv a ON ajc.lgrrec = a.lgrrec WHERE a.status <> 2 " + "INTO Table {1}", ActiveJobCosts, ActiveJobCostsTmp); //Get the list of AP lines used to generate the job costs //Include a marking if the part number is from the tax part classification //this indicates that it is a taxing part fldCount = con.ExecuteNonQuery("SELECT DISTINCT a.recnum, a.linnum, a.prtnum, NVL(t.prtcls, 0) as prtcls, a.linqty, a.linprc, a.extttl, " + "a.actnum, a.subact FROM apivln a " + "JOIN {0} ajc ON a.recnum = ajc.aprecnum " + "LEFT JOIN tkfprt t ON a.prtnum = t.recnum " + "WHERE ajc.srcnum = 11 INTO TABLE {1}", ActiveJobCostsTmp, ActiveAPLines); progress.Tick(); progress.Text = "Checking the tax accrual made on job cost"; //Mark each active job cost record as to whether there was a tax accrual/payment made on that //job cost record. This is done by counting the tax parts that were used on the invoice DataTable dtJc1 = con.GetDataTable("ActiveJobCosts1", "Select * from {0}", ActiveJobCostsTmp); foreach (DataRow dr in dtJc1.Rows) { decimal aprecNum = (decimal)dr["aprecnum"]; int count = con.GetScalar<int>("Select COUNT(*) from {0} WHERE recnum = {1} AND prtcls = {2}", ActiveAPLines, aprecNum, taxPartClass); //If count is 0 then there is no point in updating the value as it is already set to 0 by default. if (count > 0) { fldCount = con.ExecuteNonQuery("UPDATE {0} SET taxprtcnt = {1} WHERE aprecnum = {2}", ActiveJobCostsTmp, count, aprecNum); } } //TODO: This query is little too complicated. To make it simpler //Update taxacccnt DataTable dt1 = con.GetDataTable("Dt1", "SELECT * from {0} WHERE usrnme <> \"TaxAcc\"", ActiveJobCostsTmp); foreach (DataRow dr in dt1.Rows) { string taxTrnNum = (string)dr["taxtrnnum"]; //Version 1.0.8 - Should be scanning all job costs, not job costs temp for this part of the test int count = con.GetScalar<int>("SELECT COUNT(*) FROM {0} WHERE trnnum = \"{1}\" AND usrnme = \"TaxAcc\"", ActiveJobCosts, taxTrnNum); if (count > 0) { fldCount = con.ExecuteNonQuery("UPDATE {0} SET taxacccnt = {1} WHERE trnnum = \"{2}\" ", ActiveJobCostsTmp, count, taxTrnNum); } } //Check to see if each job cost has already had taxes accrued //Create list of job cost records that must be accrued with taxes fldCount = con.ExecuteNonQuery("SELECT recnum, jobnum, phsnum, trnnum, dscrpt, trndte, {0} as entdte, actprd, 31 as srcnum, 1 as status, 1 as bllsts, " + "cstcde, csttyp, cstamt as origcstamt, 00000000.00 as cstamt, 00000000.00 as blgamt, 0 as taxabl, 000 as ovrrde, \"TaxAcc\" as usrnme, " + "{1} as postyr, vndnum FROM {2} WHERE taxprtcnt = 0 AND taxacccnt = 0 AND INLIST(srcnum,11) INTO Table {3}", DateTime.Today.ToFoxproDate(), curFiscalYear, ActiveJobCostsTmp, TaxJobCosts); progress.Tick(); progress.Text = "Identifying the tax accrual records"; //Update the basic information to identify these as tax accrual records DataTable taxJobCostDt = con.GetDataTable("TaxJobCosts", "select * from {0}", TaxJobCosts); foreach (DataRow dr in taxJobCostDt.Rows) { decimal recNum = (decimal)dr["recnum"]; decimal cstType = (decimal)dr["csttyp"]; decimal origcStament = (decimal)dr["origcstamt"]; //1.0.8 - Don't truncate the transaction number, it does not need to be modified as it was originally fldCount = con.ExecuteNonQuery("UPDATE {0} SET " + "dscrpt = ALLTRIM(SUBSTR(dscrpt,1,LEN(dscrpt)-4)) + \" Tax\", " + "cstamt = origcstamt * {1}, " + "blgamt = origcstamt * {2} WHERE recnum = {3}", TaxJobCosts, (decimal)taxRates[((int)cstType - 1)], (decimal)taxRates[((int)cstType - 1)], recNum); } //Set this so that FoxPro doesn't try to insert null values in empty columns SetNullOff(con); progress.Tick(); progress.Text = "Inserting tax records"; //Add the records //int taxJobCostsCount = con.GetScalar<int>("select count(*) from {0}", TaxJobCosts); //1.0.9 - Match the vendor number from the original record in the new tax record DataTable dtTaxJobCosts = con.GetDataTable("TaxJobCosts","select * from {0}", TaxJobCosts); if (dtTaxJobCosts != null && dtTaxJobCosts.Rows.Count > 0) { fldCount = 0; foreach (DataRow dr in dtTaxJobCosts.Rows) { int recNum = con.GetScalar<int>("SELECT MAX(recnum) from jobcst") + 1; DateTime trnDate = (DateTime)dr["trndte"]; DateTime eDate = (DateTime)dr["entdte"]; decimal cost = (decimal)dr["cstamt"]; if (cost != 0) { if (dataSetVersion >= 19.2M) { con.ExecuteNonQuery("INSERT INTO jobcst ( recnum, jobnum, phsnum, trnnum, dscrpt, trndte, entdte, actprd, " + "srcnum, status, bllsts, cstcde, csttyp, cstamt, blgamt, taxabl, ovrrde, postyr, usrnme, vndnum ) " + "VALUES ({0}, {1}, {2}, \"{3}\", \"{4}\", {5}, {6}, " + "{7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15}, {16}, {17}, \"{18}\",{19}) " , recNum, dr["jobnum"], dr["phsnum"], dr["trnnum"], dr["dscrpt"], trnDate.ToFoxproDate(), eDate.ToFoxproDate(), acctPeriod, dr["srcnum"], dr["status"], dr["bllsts"], costCode, dr["csttyp"], dr["cstamt"], dr["blgamt"], dr["taxabl"], dr["ovrrde"], curFiscalYear, dr["usrnme"], dr["vndnum"]); } else { con.ExecuteNonQuery("INSERT INTO jobcst ( recnum, jobnum, phsnum, trnnum, dscrpt, trndte, entdte, actprd, " + "srcnum, status, bllsts, cstcde, csttyp, cstamt, blgamt, taxabl, ovrrde, usrnme, vndnum ) " + "VALUES ({0}, {1}, {2}, \"{3}\", \"{4}\", {5}, {6}, " + "{7}, {8}, {9}, {10}, {11}, {12}, {13}, {14}, {15}, {16}, \"{17}\", {18}) " , recNum, dr["jobnum"], dr["phsnum"], dr["trnnum"], dr["dscrpt"], trnDate.ToFoxproDate(), eDate.ToFoxproDate(), acctPeriod, dr["srcnum"], dr["status"], dr["bllsts"], costCode, dr["csttyp"], dr["cstamt"], dr["blgamt"], dr["taxabl"], dr["ovrrde"], dr["usrnme"], dr["vndnum"]); } fldCount++; } } Env.Log("{0} fields inserted in table jobcst", fldCount); } } //Set null on again SetNullOn(con); } Env.Log("Finished processing for tax liability."); }
/// <summary> /// This method updates a field "pieces" in the job cost record so we can identify which /// records should be included in a supplemental detail report. /// </summary> /// <param name="startDate"></param> /// <param name="endDate"></param> /// <param name="jobNumber"></param> /// <param name="jobPhase"></param> // 1.0.10 - Added logic to include all billed records, not just those that have had a combined // cost included in the invoice (law) public void UpdateTMTJobCost(DateTime startDate, DateTime endDate, long jobNumber, long jobPhase, ProgressDialog progress) { using (var con = SysconCommon.Common.Environment.Connections.GetOLEDBConnection()) { using ( Env.TempDBFPointer CombinedCosts = con.GetTempDBF(), AllCosts = con.GetTempDBF(), RecordList = con.GetTempDBF(), ACRInvList = con.GetTempDBF() ) { progress.Tick(); progress.Text = string.Format("Start updating the TMT job costs"); //1.0.10 All job costs that have been billed during the selected time period by the user (law) int modifiedFldCount = con.ExecuteNonQuery("SELECT * FROM jobcst WHERE status = 1 AND acrinv > 0 AND BETWEEN(trndte,{0},{1}) " + "AND usrnme <> \"Combine\" into table {2}", startDate.ToFoxproDate(), endDate.ToFoxproDate(), AllCosts); //Find all the consolidated job costs in the selected time period //That have been invoiced through T&M modifiedFldCount = con.ExecuteNonQuery("SELECT * FROM jobcst WHERE status = 1 AND acrinv > 0 AND BETWEEN(trndte,{0},{1}) " + "AND usrnme == \"Combine\" into table {2}", startDate.ToFoxproDate(), endDate.ToFoxproDate(), CombinedCosts); Env.Log("{0} T&M records found in jobcst table for updation.", modifiedFldCount); //Build a list of the job cost records that must be updated with the AR T&M invoice number con.ExecuteNonQuery("create table {0} (recnum n(10,0), acrinv n(10,0))", RecordList); progress.Tick(); progress.Text = string.Format("Reading from the memo fields of Combined Costs"); //Read each record from the memo fields of the Combined Costs DataTable _combinedCosts = con.GetDataTable("CombinedCosts", "SELECT * FROM {0}", CombinedCosts); foreach (DataRow dr in _combinedCosts.Rows) { string nteTxt = (dr != null) ? (string)dr["ntetxt"] : string.Empty; char[] delimiterChars = { '\n', '|' }; string[] nteTxts = nteTxt.Split(delimiterChars); if (nteTxts.Length >= 2) { for (int i = 1; i < nteTxts.Length; i++) { double recNum = 0.0; if (double.TryParse(nteTxts[i], out recNum)) { con.ExecuteNonQuery("INSERT INTO {0} VALUES ({1}, {2})", RecordList, recNum, dr["acrinv"]); } } } } // modifiedFldCount = con.ExecuteNonQuery("SELECT distinct acrinv FROM {0} INTO table {1}", CombinedCosts, ACRInvList); // 1.0.10 (law) the ACRInvList has to include all invoices - even if there were no combined records in those invoices modifiedFldCount = con.ExecuteNonQuery("SELECT distinct acrinv FROM {0} INTO table {1}", AllCosts, ACRInvList); progress.Tick(); progress.Text = string.Format("Updating TMT job cost records"); //Reset all the records to blank - this is specific to the list of invoices we are updating modifiedFldCount = con.ExecuteNonQuery("UPDATE jobcst SET pieces = 0 from {0} _ACRInvList WHERE jobcst.acrinv = _ACRInvList.acrinv", ACRInvList); //1.0.10 Reset all the combined records to blank - again, this must be specific to the list of invoices we are updating modifiedFldCount = con.ExecuteNonQuery("UPDATE jobcst SET pieces = 0 from {0} _RecordList WHERE _RecordList.recnum = jobcst.recnum", RecordList); //Now update the job cost records from the standardn, non-Combined records - excluding combined records modifiedFldCount = con.ExecuteNonQuery("UPDATE jobcst SET pieces = _ACRInvList.acrinv from {0} _ACRInvList WHERE jobcst.acrinv = _ACRInvList.acrinv " + "AND jobcst.usrnme <> \"Combine\"", ACRInvList); //Update the combined records modifiedFldCount = con.ExecuteNonQuery("UPDATE jobcst SET pieces = _RecordList.acrinv from {0} _RecordList WHERE _RecordList.recnum = jobcst.recnum", RecordList); Env.Log("{0} T&M records updated in jobcst table.", modifiedFldCount); } progress.Tick(); progress.Text = string.Format("Finished updating the TMT job costs"); //Set default null setting to on again SetNullOn(con); } }
/// <summary> /// Scans the jobcst data table and combines job costs into an additional record for billing purposes. /// </summary> /// <param name="startDate"></param> /// <param name="endDate"></param> /// <param name="jobNumber"></param> /// <param name="jobPhase"></para /// <param name="costCode"></param> public void ConsolidateJobCost(DateTime startDate, DateTime endDate, long jobNumber, long jobPhase, int costCode, ProgressDialog progress) { using (var con = SysconCommon.Common.Environment.Connections.GetOLEDBConnection()) { using ( Env.TempDBFPointer ActiveJobCosts = con.GetTempDBF(), MatCosts = con.GetTempDBF(), SubMatCosts = con.GetTempDBF(), NewMatCosts = con.GetTempDBF(), NewSubMatCosts = con.GetTempDBF() ) { Env.Log("Job cost consolidation started for job number: {0}", jobNumber); //Get the data set version decimal dataSetVersion = SMBHelper.GetDataSetVersion(); int curFiscalYear = 0; if (dataSetVersion == -1) { //WAIT 'Invalid data directory' window return; } //Get the current fiscal year if required if (dataSetVersion >= 19.0M) { curFiscalYear = SMBHelper.GetDataSetGLInfo("CURRENTFISCALYEAR"); } progress.Tick(); progress.Text = string.Format("Job cost consolidation started for job# {0}", jobNumber); jobPhase = 0; int modifiedFldCount = 0; //Get list of active job cost records to be billed modifiedFldCount = con.ExecuteNonQuery("SELECT * FROM jobcst WHERE jobnum = {0} " + "AND phsnum = {1} AND status = 1 AND bllsts = 1 " + "AND jobcst.trndte >= {2} AND jobcst.trndte <= {3} AND usrnme <> \"Combine\" INTO TABLE {4}", jobNumber, jobPhase, startDate.ToFoxproDate(), endDate.ToFoxproDate(), ActiveJobCosts); progress.Tick(); progress.Text = string.Format("Getting list of contract and subcontract material records\n to be combined by cost code"); //Get the list of Material Records to be combined by cost type modifiedFldCount = con.ExecuteNonQuery("SELECT * FROM {0} WHERE csttyp = 1 INTO TABLE {1}", ActiveJobCosts, MatCosts); //Get the list of Subcontract Material Records to be combined by cost type modifiedFldCount = con.ExecuteNonQuery("SELECT * FROM {0} WHERE csttyp = 7 INTO TABLE {1}", ActiveJobCosts, SubMatCosts); progress.Tick(); progress.Text = string.Format("Consolidating into a single billing record"); // DataTable _matCosts = con.GetDataTable("MatCosts", "Select * from {0}", MatCosts); string MatCostDetail = "The following job cost records have been consolidated into a single billing record:" + "|"; foreach (DataRow dr in _matCosts.Rows) { MatCostDetail = MatCostDetail + Convert.ToString(dr["recnum"]).PadLeft(7) + "|"; } Env.Log("Material cost detail memo: {0}", MatCostDetail); DataTable _subMatCosts = con.GetDataTable("MatCosts", "Select * from {0}", SubMatCosts); string SubMatDetail = "The following job cost records have been consolidated into a single billing record:" + "|"; foreach (DataRow dr in _subMatCosts.Rows) { SubMatDetail = SubMatDetail + Convert.ToString(dr["recnum"]).PadLeft(7) + "|"; } Env.Log("Sub-material cost detail memo: {0}", SubMatDetail); progress.Tick(); progress.Text = string.Format("Combining material costs into a single record"); // Combine the material costs into two records for appending to the actual job costs //There is some special math here that will ensure that if the user recalculates the //t&m records, the billing total will be correct. //LOCAL ARRAY tvalue(1,1) //Combine the material costs into a single record for appending to the actual job costs int matCostCount = con.GetScalar<int>("select count(*) from {0}", MatCosts); if (matCostCount > 0) { decimal sumBlgAmt = 0.0m; decimal sumBlgTotal = 0.0m; decimal recBillAmout = 0.0m; sumBlgAmt = con.GetScalar<decimal>("SELECT SUM(blgamt) FROM {0}", MatCosts); sumBlgTotal = con.GetScalar<decimal>("SELECT SUM(blgttl) FROM {0}", MatCosts); if (sumBlgTotal != 0.0m) { recBillAmout = (sumBlgAmt * sumBlgAmt) / sumBlgTotal; recBillAmout = Math.Round(recBillAmout, 2); } string formattedED = string.Format("'{0} {1}'", endDate.ToString("MM/dd/yy"), "Mat"); #region "Ver 1.0.2" //modifiedFldCount = con.ExecuteNonQuery("SELECT {0} as jobnum, {1} as phsnum, {2} as trnnum, \"Materials\" as dscrpt, {3} as trndte," // + "{4} as entdte, MAX(actprd) as actprd, 31 as srcnum, 1 as status, 1 as bllsts," // + "{5} as cstcde, 1 as csttyp, SUM(cstamt) as blgamt, SUM(blgttl) as blgttl, SUM(shwamt) as shwamt, SUM(ovhamt) as ovhamt, " // + "SUM(pftamt) as pftamt, 1 as ovrrde, \"Combine\" as usrnme FROM {6} INTO TABLE {7}", // jobNumber, jobPhase, formattedED, endDate.ToFoxproDate(), DateTime.Today.ToFoxproDate(), costCode, MatCosts, NewMatCosts); #endregion #region "Ver 1.0.3 onwards" //Create the first record which will be the non-taxable amount of the combined materials modifiedFldCount = con.ExecuteNonQuery("SELECT {0} as jobnum, {1} as phsnum, {2} as trnnum, \"Materials\" as dscrpt, {3} as trndte," + "{4} as entdte, MAX(actprd) as actprd, 31 as srcnum, 1 as status, 1 as bllsts," + "{5} as cstcde, 1 as csttyp, {6} as blgamt, {7} as blgttl, 0 as taxabl," + " 1 as ovrrde, {8} as postyr, \"Combine\" as usrnme FROM {9} INTO TABLE {10}", jobNumber, jobPhase, formattedED, endDate.ToFoxproDate(), DateTime.Today.ToFoxproDate(), costCode, recBillAmout, sumBlgAmt, curFiscalYear, MatCosts, NewMatCosts); //Create the second record which will be the taxable amount of the combined materials. //NOTE: THE COST TYPE IS GOING TO BE 5 FOR THIS RECORD, NOT 1 LIKE THE ABOVE RECORD. recBillAmout = 0.0m; formattedED = string.Format("'{0} {1}'", endDate.ToString("MM/dd/yy"), "MSrv"); decimal blgTotal = sumBlgTotal - sumBlgAmt; if ((sumBlgTotal != 0.0m) && (sumBlgAmt != 0.0m)) { recBillAmout = (sumBlgTotal - sumBlgAmt) / (sumBlgTotal / sumBlgAmt); recBillAmout = Math.Round(recBillAmout, 2); } modifiedFldCount = con.ExecuteNonQuery("INSERT INTO {0} SELECT {1} as jobnum, {2} as phsnum, {3} as trnnum, \"Materials Service\" as dscrpt, {4} as trndte," + "{5} as entdte, MAX(actprd) as actprd, 31 as srcnum, 1 as status, 1 as bllsts," + "{6} as cstcde, 5 as csttyp, {7} as blgamt, {8} as blgttl, 1 as taxabl, " + " 1 as ovrrde, {9} as postyr, \"Combine\" as usrnme FROM {10}", NewMatCosts, jobNumber, jobPhase, formattedED, endDate.ToFoxproDate(), DateTime.Today.ToFoxproDate(), costCode, recBillAmout, blgTotal, curFiscalYear, MatCosts); #endregion } int subMatCostCount = con.GetScalar<int>("select count(*) from {0}", SubMatCosts); if (subMatCostCount > 0) { decimal sumBlgAmt = 0.0m; decimal sumBlgTotal = 0.0m; decimal recBillAmout = 0.0m; sumBlgAmt = con.GetScalar<decimal>("SELECT SUM(blgamt) FROM {0}", SubMatCosts); sumBlgTotal = con.GetScalar<decimal>("SELECT SUM(blgttl) FROM {0}", SubMatCosts); if (sumBlgTotal != 0.0m) { recBillAmout = (sumBlgAmt * sumBlgAmt) / sumBlgTotal; recBillAmout = Math.Round(recBillAmout, 2); } string formattedED = string.Format("'{0} {1}'", endDate.ToString("MM/dd/yy"), "SubMat"); #region "Ver 1.0.2" //modifiedFldCount = con.ExecuteNonQuery("SELECT {0} as jobnum, {1} as phsnum, {2} as trnnum, \"Subcontract Materials\" as dscrpt, " // + "{3} as trndte, {4} as entdte, MAX(actprd) as actprd, 31 as srcnum, 1 as status, 1 as bllsts, " // + "{5} as cstcde, 7 as csttyp, SUM(cstamt) as blgamt, SUM(blgttl) as blgttl, SUM(shwamt) as shwamt, SUM(ovhamt) as ovhamt, " // + "SUM(pftamt) as pftamt, 1 as ovrrde, \"Combine\" as usrnme FROM {6} INTO TABLE {7}", // jobNumber, jobPhase, formattedED, endDate.ToFoxproDate(), DateTime.Today.ToFoxproDate(), costCode, SubMatCosts, NewSubMatCosts); #endregion #region "Ver 1.0.3 onwards" //Create the first record which will be the non-taxable amount of the combined materials modifiedFldCount = con.ExecuteNonQuery("SELECT {0} as jobnum, {1} as phsnum, {2} as trnnum, \"Subcontract Materials\" as dscrpt, {3} as trndte," + "{4} as entdte, MAX(actprd) as actprd, 31 as srcnum, 1 as status, 1 as bllsts, " + "{5} as cstcde, 7 as csttyp, {6} as blgamt, {7} as blgttl, 0 as taxabl, " + " 1 as ovrrde, {8} as postyr, \"Combine\" as usrnme FROM {9} INTO TABLE {10}", jobNumber, jobPhase, formattedED, endDate.ToFoxproDate(), DateTime.Today.ToFoxproDate(), costCode, recBillAmout, sumBlgAmt, curFiscalYear, SubMatCosts, NewSubMatCosts); //Create the second record which will be the taxable amount of the combined materials. //NOTE: THE COST TYPE IS GOING TO BE 5 FOR THIS RECORD, NOT 1 LIKE THE ABOVE RECORD. recBillAmout = 0.0m; formattedED = string.Format("'{0} {1}'", endDate.ToString("MM/dd/yy"), "SubMSrv"); decimal blgTotal = sumBlgTotal - sumBlgAmt; if ((sumBlgTotal != 0.0m) && (sumBlgAmt != 0.0m)) { recBillAmout = (sumBlgTotal - sumBlgAmt) / (sumBlgTotal / sumBlgAmt); recBillAmout = Math.Round(recBillAmout, 2); } // With version 1.0.5, this second created record, Subcontractor Materials Service, is going // to be to cost type 8 to separate // it from the Materials Service element of the project. Prior to version 1.0.5, it was going // going to cost type 5. modifiedFldCount = con.ExecuteNonQuery("INSERT INTO {0} SELECT {1} as jobnum, {2} as phsnum," + "{3} as trnnum, \"Subcontract Materials Service\" as dscrpt, {4} as trndte," + "{5} as entdte, MAX(actprd) as actprd, 31 as srcnum, 1 as status, 1 as bllsts," + "{6} as cstcde, 8 as csttyp, {7} as blgamt, {8} as blgttl, 1 as taxabl, " + " 1 as ovrrde, {9} as postyr, \"Combine\" as usrnme FROM {10}", NewSubMatCosts, jobNumber, jobPhase, formattedED, endDate.ToFoxproDate(), DateTime.Today.ToFoxproDate(), costCode, recBillAmout, blgTotal, curFiscalYear, SubMatCosts); #endregion } SetNullOff(con); progress.Tick(); progress.Text = string.Format("Inserting material cost records into jobcst table"); if (System.IO.File.Exists(NewMatCosts.filename)) { DataTable matCostDetails = con.GetDataTable("TaxJobCosts", "select * from {0}", NewMatCosts); if (matCostDetails != null && matCostDetails.Rows.Count > 0) { //Add the recnum and ntetxt column matCostDetails.Columns.Add("recnum", typeof(decimal)); matCostDetails.Columns.Add("ntetxt"); if (dataSetVersion < 19.0M) { matCostDetails.Columns.Remove("postyr"); } foreach (DataRow dr in matCostDetails.Rows) { int recNum = con.GetScalar<int>("SELECT MAX(recnum) from jobcst") + 1; //DateTime trnDate = (DateTime)dr["trndte"]; //DateTime eDate = (DateTime)dr["entdte"]; ////Using standard way to insert data //var jobcst_row = con.GetDataTable("Job Cost", "select * from {0} where recnum = {0}", NewMatCosts, dr["recnum"]).Rows[0]; //jobcst_row["recnum"] = recNum; //jobcst_row["jobnum"] = dr["jobnum"]; //jobcst_row["phsnum"] = dr["phsnum"]; //jobcst_row["trnnum"] = dr["trnnum"]; //jobcst_row["dscrpt"] = dr["dscrpt"]; //jobcst_row["trndte"] = trnDate.ToFoxproDate(); //jobcst_row["entdte"] = eDate.ToFoxproDate(); //jobcst_row["actprd"] = dr["actprd"]; //jobcst_row["srcnum"] = dr["srcnum"]; //jobcst_row["status"] = dr["status"]; //jobcst_row["bllsts"] = dr["bllsts"]; //jobcst_row["cstcde"] = dr["cstcde"]; //jobcst_row["blgamt"] = dr["blgamt"]; //jobcst_row["ovrrde"] = dr["ovrrde"]; //jobcst_row["usrnme"] = dr["usrnme"]; //jobcst_row["ntetxt"] = MatCostDetail; //// insert the record //var sql = jobcst_row.FoxproInsertString("jobcst"); //con.ExecuteNonQuery(sql); // insert the record dr["recnum"] = recNum; dr["ntetxt"] = MatCostDetail; var sql = dr.FoxproInsertString("jobcst"); con.ExecuteNonQuery(sql); modifiedFldCount++; } } } progress.Tick(); progress.Text = string.Format("Inserting sub material cost records into jobcst table"); if (System.IO.File.Exists(NewSubMatCosts.filename)) { DataTable subMatCostDetails = con.GetDataTable("TaxJobCosts", "select * from {0}", NewSubMatCosts); if (subMatCostDetails != null && subMatCostDetails.Rows.Count > 0) { //Add the recnum and ntetxt column subMatCostDetails.Columns.Add("recnum", typeof(decimal)); subMatCostDetails.Columns.Add("ntetxt"); if (dataSetVersion < 19.0M) { subMatCostDetails.Columns.Remove("postyr"); } foreach (DataRow dr in subMatCostDetails.Rows) { int recNum = con.GetScalar<int>("SELECT MAX(recnum) from jobcst") + 1; //DateTime trnDate = (DateTime)dr["trndte"]; //DateTime eDate = (DateTime)dr["entdte"]; //Working Query //modifiedFldCount = con.ExecuteNonQuery("INSERT INTO jobcst ( recnum, jobnum, phsnum, trnnum, dscrpt, trndte, entdte, actprd, srcnum, " // + "status, bllsts, cstcde, csttyp, blgamt, ovrrde, usrnme, ntetxt ) " // + "VALUES ({0}, {1}, {2}, \"{3}\", \"{4}\", {5}, {6}, {7}, {8}, " // + "{9}, {10}, {11}, {12}, {13}, {14}, \"{15}\", \"{16}\")", // recNum, dr["jobnum"], dr["phsnum"], dr["trnnum"], dr["dscrpt"], trnDate.ToFoxproDate(), // eDate.ToFoxproDate(), dr["actprd"], dr["srcnum"], dr["status"], dr["bllsts"], dr["cstcde"], // dr["csttyp"], dr["blgamt"], dr["ovrrde"], dr["usrnme"], SubMatDetail); // insert the record dr["recnum"] = recNum; dr["ntetxt"] = SubMatDetail; var sql = dr.FoxproInsertString("jobcst"); con.ExecuteNonQuery(sql); modifiedFldCount++; } } } //Finally, set all the billing status to non-billable for materials and subcontract materiasl modifiedFldCount = con.ExecuteNonQuery("UPDATE jobcst SET jobcst.bllsts = 2 from {0} _ActiveJobCosts WHERE jobcst.recnum = _ActiveJobCosts.recnum " + "AND INLIST(_ActiveJobCosts.csttyp,1,7)", ActiveJobCosts); Env.Log("Updated billing status of {0} records in jobcst table.", modifiedFldCount); } //update the job cost tax status UpdateJobCostTaxStatus(jobNumber, startDate, endDate, con); Env.Log("--------------------------------------------------------------------------------\n"); } }
private void PopulateTemplate(string template, long[] jobnums, int strprd, int endprd, DateTime trndate, decimal[] nonbillablecstcdes) { using (var con = SysconCommon.Common.Environment.Connections.GetOLEDBConnection()) { using (Env.TempDBFPointer _jobcst = con.GetTempDBF(), _jobnums = con.GetTempDBF(), _blgqty = con.GetTempDBF(), _nobill = con.GetTempDBF(), _sources = con.GetTempDBF(), _csttyps = con.GetTempDBF(), _phases = con.GetTempDBF()) { using (var progress = new ProgressDialog(9)) { progress.Text = "Select Job Cost Records"; progress.Show(); // first create a table of job numbers to join against con.ExecuteNonQuery("create table {0} (jobnum n(10,0) not null)", _jobnums); foreach(var j in jobnums) { con.ExecuteNonQuery("insert into {0} (jobnum) values ({1})", _jobnums, j); } con.ExecuteNonQuery("select" + " jobcst.recnum" + ", actrec.estemp as estnum" + ", jobcst.empnum" + ", jobcst.vndnum" + ", jobcst.eqpnum" + ", 000000 as tmemln" + ", 000000 as tmeqln" + ", jobcst.jobnum" + ", actrec.jobnme" + ", alltrim(reccln.clnnme) as clnnme" + ", jobcst.trnnum" + ", jobcst.dscrpt" + ", jobcst.trndte" + ", jobcst.actprd" + ", jobcst.srcnum" + ", jobcst.status" + ", jobcst.bllsts" + ", jobcst.phsnum" + ", jobphs.phsnme" + ", jobcst.cstcde" + ", cstcde.cdenme" + ", jobcst.csttyp" + ", jobcst.csthrs" + ", IIF(jobcst.acrinv = 0 AND jobcst.bllsts = 1 AND jobcst.csttyp = 2" + ", jobcst.blgqty" + ", 0000000000) as blgpnd" + ", jobcst.eqpqty" + ", jobcst.blgqty" + ", jobcst.paytyp" + ", jobcst.cstamt" + ", jobcst.blgttl" + ", jobcst.acrinv" + ", IIF(" + "jobcst.csttyp = 2, 'Employee '," + "IIF(jobcst.csttyp = 3, 'Equipment '," + "IIF(jobcst.empnum <> 0, 'Employee '," + "IIF(jobcst.eqpnum <> 0, 'Equipment '," + "IIF(jobcst.vndnum <> 0, 'Vendor '," + "'None '))))) as empeqpvnd" + ", [ ] as ename" + ", 00000000.00000000 as rate01" + ", 00000000.00000000 as rate02" + ", 00000000.00000000 as rate03" + ", 00000000.00000000 as minhrs" + ", 00000001.00000000 as markup" + ", 0000000000000.00000000 as estbll" + ", jobcst.eqpnum" + ", eqpmnt.eqpnme" + ", jobcst.blgunt" + ", jobcst.empnum" + ", employ.fullst" + ", jobcst.blgamt" + ", jobcst.ntetxt" + ", estmtr.fullst as estnme" + ", nvl(sprvsr.fullst, [No Supervisor ]) as sprvsr" + " from jobcst" + " join actrec on jobcst.jobnum = actrec.recnum" + " join reccln on reccln.recnum = actrec.clnnum" + " left outer join employ estmtr on actrec.estemp = estmtr.recnum" + " left join employ sprvsr on actrec.sprvsr = sprvsr.recnum" + " left join cstcde on cstcde.recnum = jobcst.cstcde" + " join {0} _jobnums on _jobnums.jobnum = jobcst.jobnum" + " left join eqpmnt on eqpmnt.recnum = jobcst.eqpnum" + " left join employ on employ.recnum = jobcst.empnum" + " left join jobphs on jobphs.recnum = jobcst.jobnum and jobphs.phsnum = jobcst.phsnum" // + " and between(jobcst.actprd, {1}, {2})" + " where jobcst.actprd >= {1}" + (chkUnbilled.Checked ? " and jobcst.bllsts = 1" : "") + " and jobcst.actprd <= {2}" + " and jobcst.status <> 2" + " and jobcst.trndte <= {3}" + " order by jobcst.recnum" + " into table {4}" , _jobnums, strprd, endprd, trndate.ToFoxproDate(), _jobcst); progress.Tick(); progress.Text = "Selecting Names"; con.ExecuteNonQuery("update _jobcst set ename = alltrim(str(empnum)) + [ - ] + alltrim(employ.fullst)" + " from {0} _jobcst" + " join employ on _jobcst.empnum = employ.recnum" + " where empeqpvnd = 'Employee'" , _jobcst); con.ExecuteNonQuery("update _jobcst set ename = alltrim(str(vndnum)) + [ - ] + alltrim(actpay.vndnme)" + " from {0} _jobcst" + " join actpay on _jobcst.vndnum = actpay.recnum" + " where empeqpvnd = 'Vendor'" , _jobcst); con.ExecuteNonQuery("update _jobcst set ename = alltrim(str(eqpnum)) + [ - ] + alltrim(eqpmnt.eqpnme)" + " from {0} _jobcst" + " join eqpmnt on _jobcst.eqpnum = eqpmnt.recnum" + " where empeqpvnd = 'Equipment'" , _jobcst); progress.Tick(); progress.Text = "Locating T&M Line items"; con.ExecuteNonQuery("update _jobcst set _jobcst.tmemln = tmemln.linnum" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " join tmemln on" + " tmemln.recnum = timmat.emptbl" + " and timmat.emptbl <> 0" + " and tmemln.empnum = 0" + " and tmemln.cstcde = _jobcst.cstcde" + " where _jobcst.csttyp = 2" , _jobcst); con.ExecuteNonQuery("update _jobcst set _jobcst.tmemln = tmemln.linnum" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " join tmemln on" + " tmemln.recnum = timmat.emptbl" + " and timmat.emptbl <> 0" + " and tmemln.empnum = _jobcst.empnum" + " and tmemln.cstcde = _jobcst.cstcde" + " where _jobcst.empnum <> 0 AND _jobcst.csttyp = 2" , _jobcst); con.ExecuteNonQuery("update _jobcst set _jobcst.tmeqln = tmeqln.linnum" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " join tmeqln on tmeqln.recnum = timmat.eqptbl" , _jobcst); progress.Tick(); progress.Text = "Loading T&M Rates"; con.ExecuteNonQuery("update _jobcst set" + " _jobcst.rate01 = tmeqln.oprrte" + ", _jobcst.rate02 = tmeqln.stdrte" + ", _jobcst.rate03 = tmeqln.idlrte" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " join tmeqln on tmeqln.recnum = timmat.eqptbl and tmeqln.linnum = _jobcst.tmeqln" + " where _jobcst.tmeqln <> 0" , _jobcst); con.ExecuteNonQuery("update _jobcst set" + " _jobcst.rate01 = tmemln.rate01" + ", _jobcst.rate02 = tmemln.rate02" + ", _jobcst.rate03 = tmemln.rate03" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " join tmemln on tmemln.recnum = timmat.emptbl and tmemln.linnum = _jobcst.tmemln" + " where _jobcst.tmemln <> 0" , _jobcst); progress.Tick(); progress.Text = "Loading Minimum Hours"; con.ExecuteNonQuery("update _jobcst set _jobcst.minhrs = tmeqln.minhrs" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " join tmeqln on tmeqln.recnum = timmat.eqptbl and tmeqln.linnum = _jobcst.tmeqln" + " where _jobcst.tmeqln <> 0" , _jobcst); con.ExecuteNonQuery("update _jobcst set _jobcst.minhrs = tmemln.minhrs" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " join tmemln on tmemln.recnum = timmat.emptbl and tmemln.linnum = _jobcst.tmemln" + " where _jobcst.tmemln <> 0" , _jobcst); progress.Tick(); progress.Text = "Selecting Markup Values"; con.ExecuteNonQuery("update _jobcst set _jobcst.markup =" + " (1.00 + (timmat.mtrhdn / 100.00)) *" + " (1.00 + (timmat.mtrshw / 100.00)) *" + " (1.00 + (timmat.mtrovh / 100.00)) *" + " (1.00 + (timmat.mtrpft / 100.00))" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " where _jobcst.csttyp = 1" , _jobcst); con.ExecuteNonQuery("update _jobcst set _jobcst.markup =" + " (1.00 + (timmat.labhdn / 100.00)) *" + " (1.00 + (timmat.labshw / 100.00)) *" + " (1.00 + (timmat.labovh / 100.00)) *" + " (1.00 + (timmat.labpft / 100.00))" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " where _jobcst.csttyp = 2" , _jobcst); con.ExecuteNonQuery("update _jobcst set _jobcst.markup =" + " (1.00 + (timmat.eqphdn / 100.00)) *" + " (1.00 + (timmat.eqpshw / 100.00)) *" + " (1.00 + (timmat.eqpovh / 100.00)) *" + " (1.00 + (timmat.eqppft / 100.00))" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " where _jobcst.csttyp = 3" , _jobcst); con.ExecuteNonQuery("update _jobcst set _jobcst.markup =" + " (1.00 + (timmat.subhdn / 100.00)) *" + " (1.00 + (timmat.subshw / 100.00)) *" + " (1.00 + (timmat.subovh / 100.00)) *" + " (1.00 + (timmat.subpft / 100.00))" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " where _jobcst.csttyp = 4" , _jobcst); con.ExecuteNonQuery("update _jobcst set _jobcst.markup =" + " (1.00 + (timmat.otrhdn / 100.00)) *" + " (1.00 + (timmat.otrshw / 100.00)) *" + " (1.00 + (timmat.otrovh / 100.00)) *" + " (1.00 + (timmat.otrpft / 100.00))" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " where _jobcst.csttyp = 5" , _jobcst); con.ExecuteNonQuery("update _jobcst set _jobcst.markup =" + " (1.00 + (timmat.cs6hdn / 100.00)) *" + " (1.00 + (timmat.cs6shw / 100.00)) *" + " (1.00 + (timmat.cs6ovh / 100.00)) *" + " (1.00 + (timmat.cs6pft / 100.00))" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " where _jobcst.csttyp = 6" , _jobcst); con.ExecuteNonQuery("update _jobcst set _jobcst.markup =" + " (1.00 + (timmat.cs7hdn / 100.00)) *" + " (1.00 + (timmat.cs7shw / 100.00)) *" + " (1.00 + (timmat.cs7ovh / 100.00)) *" + " (1.00 + (timmat.cs7pft / 100.00))" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " where _jobcst.csttyp = 7" , _jobcst); con.ExecuteNonQuery("update _jobcst set _jobcst.markup =" + " (1.00 + (timmat.cs8hdn / 100.00)) *" + " (1.00 + (timmat.cs8shw / 100.00)) *" + " (1.00 + (timmat.cs8ovh / 100.00)) *" + " (1.00 + (timmat.cs8pft / 100.00))" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " where _jobcst.csttyp = 8" , _jobcst); // BUG in SMB database, cs9pft is type C!!!! con.ExecuteNonQuery("update _jobcst set _jobcst.markup =" + " (1.00 + (timmat.cs9hdn / 100.00)) *" + " (1.00 + (timmat.cs9shw / 100.00)) *" + " (1.00 + (timmat.cs9ovh / 100.00)) *" + " (1.00 + (val(timmat.cs9pft) / 100.00))" + " from {0} _jobcst" + " join timmat on timmat.recnum = _jobcst.jobnum" + " where _jobcst.csttyp = 9" , _jobcst); progress.Tick(); progress.Text = "Selecting Billing Quantities"; con.ExecuteNonQuery("select _jobcst.recnum, 00000000.00000000 as hrs, cast(null as n(3)) as typ from {0} _jobcst into table {1}", _jobcst, _blgqty); con.ExecuteNonQuery("update blgqty set hrs = _jobcst.csthrs, typ = _jobcst.paytyp" + " from {0} blgqty" + " join {1} _jobcst on blgqty.recnum = _jobcst.recnum" + " where _jobcst.csttyp = 2" , _blgqty, _jobcst); con.ExecuteNonQuery("update blgqty set hrs = _jobcst.blgqty, typ = _jobcst.paytyp" + " from {0} blgqty" + " join {1} _jobcst on blgqty.recnum = _jobcst.recnum" + " where _jobcst.csttyp = 2 and blgqty.hrs = 0 and _jobcst.bllsts = 1" , _blgqty, _jobcst); con.ExecuteNonQuery("update blgqty set hrs = _jobcst.eqpqty, typ = eqpmnt.eqptyp" + " from {0} blgqty" + " join {1} _jobcst on blgqty.recnum = _jobcst.recnum" + " join eqpmnt on _jobcst.eqpnum = eqpmnt.recnum" + " where _jobcst.csttyp = 3 and _jobcst.eqpnum <> 0 and eqpmnt.eqptyp <> 0" , _blgqty, _jobcst); progress.Tick(); progress.Text = "Calculating Billing Amounts"; con.ExecuteNonQuery("update _jobcst set _jobcst.estbll = " + "IIF(typ = 1 and rate01 <> 0, hrs*rate01," + "IIF(typ = 2 and rate02 <> 0, hrs*rate02," + "IIF(typ = 3 and rate03 <> 0, hrs*rate03," + "cstamt)))" + " from {0} _jobcst" + " join {1} blgqty on blgqty.recnum = _jobcst.recnum" , _jobcst, _blgqty); con.ExecuteNonQuery("update _jobcst set estbll = cstamt" + " from {0} _jobcst" + " join eqpmnt on eqpmnt.recnum = _jobcst.eqpnum" + " where _jobcst.csttyp = 3 and (isnull(eqpmnt.eqptyp) or eqpmnt.eqptyp = 0)" , _jobcst); con.ExecuteNonQuery("update {0} set estbll = estbll * markup", _jobcst); con.ExecuteNonQuery("update {0} set estbll = 0 where bllsts = 2", _jobcst); con.ExecuteNonQuery("update {0} set estbll = blgttl where bllsts = 3", _jobcst); con.ExecuteNonQuery("update {0} set estbll = blgamt where estbll = 0", _jobcst); // build a list of nonbillable cost codes con.ExecuteNonQuery("create table {0} (cstcde n(18,3) not null)", _nobill); foreach (var cstcde in nonbillablecstcdes) { con.ExecuteNonQuery("insert into {0} (cstcde) values ({1})", _nobill, cstcde); } // make sure those cost codes are not billed con.ExecuteNonQuery("update _jobcst set estbll = 0 from {0} _jobcst join {1} _nobill on _nobill.cstcde = _jobcst.cstcde" + " where _jobcst.acrinv = 0" , _jobcst, _nobill); // set their bllsts to unbillable cost code // v2.1.2 BUT only for items that have not already been invoiced con.ExecuteNonQuery("update _jobcst set bllsts = 4 from {0} _jobcst join {1} _nobill on _nobill.cstcde = _jobcst.cstcde" + " where _jobcst.acrinv = 0" , _jobcst, _nobill); progress.Tick(); progress.Text = "Selecting References"; con.ExecuteNonQuery("select distinct _jobcst.srcnum as recnum, source.srcnme, source.srcdsc" + " from {0} _jobcst" + " left join source on source.recnum = _jobcst.srcnum" + " into table {1}" , _jobcst, _sources); con.ExecuteNonQuery("select distinct _jobcst.csttyp as recnum, csttyp.typnme" + " from {0} _jobcst" + " left join csttyp on csttyp.recnum = _jobcst.csttyp" + " into table {1}" , _jobcst, _csttyps); con.ExecuteNonQuery("select distinct _jobcst.phsnum, jobphs.phsnme, alltrim(str(_jobcst.phsnum)) + [ - ] + alltrim(jobphs.phsnme) as phsdsc" + " from {0} _jobcst" + " join jobphs on jobphs.recnum = _jobcst.jobnum and jobphs.phsnum = _Jobcst.phsnum" + " into table {1}" , _jobcst, _phases); con.ExecuteNonQuery("insert into {0} (phsnum, phsnme, phsdsc) values (0, [None], [0 - None])", _phases); /* if we want a summary, do the totals now */ var is_summary = chkSumCustomer.Checked || chkSumJob.Checked || chkSumPeriod.Checked; Env.TempDBFPointer _jobcstsum = null; if (is_summary) { var groupCols = new List<string>(); if(chkSumCustomer.Checked) groupCols.Add("clnnme"); if (chkSumJob.Checked) { groupCols.Add("jobnum"); groupCols.Add("jobnme"); groupCols.Add("clnnme"); } if(chkSumPeriod.Checked) groupCols.Add("actprd"); var sum_cols = new string[] { "cstamt", "blgttl", "estbll", "blgqty", "blgpnd", "blgamt" }; _jobcstsum = con.Summarize(_jobcst, groupCols.Uniq().ToArray(), sum_columns: sum_cols); } progress.Tick(); progress.Text = "Loading Excel Sheet"; ExcelAddinUtil.UseNewApp(); try { var details_dt = con.GetDataTable("Details", "select * from {0}", _jobcstsum != null ? _jobcstsum : _jobcst); details_dt.ConfigurableWriteToExcel(template, "ImportData", "DetailData"); var sources_dt = con.GetDataTable("Sources", "select * from {0}", _sources); sources_dt.ConfigurableWriteToExcel(template, "References", "Sources"); var csttyps_dt = con.GetDataTable("Cost Types", "select * from {0}", _csttyps); csttyps_dt.ConfigurableWriteToExcel(template, "References", "CostTypes"); var jobphs_dt = con.GetDataTable("Phases", "select * from {0}", _phases); jobphs_dt.ConfigurableWriteToExcel(template, "References", "JobPhases"); ExcelAddinUtil.app.Visible = true; // auto-fit row heights ExcelAddinUtil.app.ActiveWorkbook.getWorksheet("Job Detail").Cells.Rows.AutoFit(); // if the template has the unbilled by job pivot table, go ahead and set it's settings try { if (_jobcstsum == null) { /* set the pivot table options and refresh data for the unbilled by job sheet */ var unbilled_ptable = ExcelAddinUtil.app.ActiveWorkbook.getWorksheet("Unbilled By Job").PivotTables("ByJob"); unbilled_ptable.PivotCache.Refresh(); /* set the billing status filter to 'Unbilled' */ unbilled_ptable.PivotFields("Billing Status").ClearAllFilters(); unbilled_ptable.PivotFields("Billing Status").CurrentPage = "Unbilled"; /* sort the pivot table by date */ unbilled_ptable.PivotFields("Date").AutoSort(1, "Date"); /* hide the "Job" that shows up for unpopulated rows in the source data */ var missing = Missing.Value; unbilled_ptable.PivotFields("Job").PivotFilters.Add(16, missing, "0 - 0 - 0 - 0", missing, missing, missing, missing, missing); /* collapse to dates */ unbilled_ptable.PivotFields("Date").ShowDetail = false; /* format numbers in the pivot table */ Worksheet ws = ExcelAddinUtil.app.ActiveWorkbook.getWorksheet("Unbilled By Job"); Range r = ws.get_Range("B:H"); r.NumberFormat = "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)"; r = ws.get_Range("D:D,B:B"); r.NumberFormat = "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)"; } } catch { } } finally { ExcelAddinUtil.app.Visible = true; } } } } }
private void import_file(string filename) { using (var progress = new ProgressDialog(3)) { progress.Show(); progress.Text = "Copying Required Files"; progress.Tick(); // first, make sure the audit log exists if (!File.Exists(mbapi.smartGetSMBDir() + "/syscon_tm_log.DBF")) { File.Copy(Env.GetEXEDirectory() + "/syscon_tm_log.DBF", mbapi.smartGetSMBDir() + "/syscon_tm_log.DBF"); File.Copy(Env.GetEXEDirectory() + "/syscon_tm_log.FPT", mbapi.smartGetSMBDir() + "/syscon_tm_log.FPT"); } // make a copy of the import file into Datadir + /Syscon TM Audit/<date>.xlsm try { if (!Directory.Exists(mbapi.smartGetSMBDir() + "/Syscon TM Audit")) Directory.CreateDirectory(mbapi.smartGetSMBDir() + "/Syscon TM Audit"); var today = DateTime.Today; var dtestr = string.Format("{0}-{1}-{2}", today.Year, today.Month, today.Day); int index = 1; var ext = Path.GetExtension(filename); var new_filename = string.Format("{0}/Syscon TM Audit/{1}_{2}{3}", mbapi.smartGetSMBDir(), dtestr, index, ext); while (File.Exists(new_filename)) { new_filename = string.Format("{0}/Syscon TM Audit/{1}_{2}{3}", mbapi.smartGetSMBDir(), dtestr, ++index, ext); } File.Copy(filename, new_filename); filename = new_filename; } catch (Exception ex) { MessageBox.Show("Could not copy the file for auditing purposes, not updating SMB.\r\nPlease ensure the file is closed and try again.", "Error", MessageBoxButtons.OK); Env.Log("{0}\r\n{1}", ex.Message, ex.StackTrace); return; } var import_errors = false; using (var excel_con = SysconCommon.Common.Environment.Connections.GetInMemoryDB()) { using (var mb7_con = SysconCommon.Common.Environment.Connections.GetOLEDBConnection()) { progress.Text = "Loading Excel (May take a while)"; progress.Tick(); // load the excel_con with values ExcelAddinUtil.UseNewApp(_readonly: true); try { var tempdt = ExcelAddinUtil.GetNamedRangeData(filename, "Change Summary", "ChangeSummary", true); excel_con.LoadDataTable(tempdt); } finally { ExcelAddinUtil.CloseApp(false); } progress.Text = "Loading data into SMB"; progress.Tick(); // wrap it all in a transaction, so that if one thing fails, the db is not left in a corrupted state // ARGHHH!!! Stupid SMB uses free tables, (no .dbc) so the rollback() seems to succeed but doesn't actually // do anything.... god i hate Sage sometimes try { // make sure there are approved changes to update var chngrows_count = excel_con.GetScalar<int>("select count(*) from ChangeSummary where invalid = 0 and apprvd = 'Yes'"); if (chngrows_count == 0) { MessageBox.Show("No approved changes in spreadsheet.", "Error", MessageBoxButtons.OK); return; } Func<string, long, bool> auditlog = (string msg, long recnum) => { try { mb7_con.ExecuteNonQuery("insert into syscon_tm_log (recnum, usrnme, chgdsc, chgdte, chgpth) values ({0}, {1}, {2}, {3}, {4})" , recnum , mbapi.LoggedInUser.FoxproQuote() , msg.FoxproQuote() , DateTime.Today.ToFoxproDate() , filename.FoxproQuote()); return true; } catch (Exception ex) { Env.Log("{0}\r\n{1}", ex.Message, ex.StackTrace); import_errors = true; return false; } }; // update billing status var data_dt = excel_con.GetDataTable("Billing Status", "select recnum, bllsts from ChangeSummary where mbllsts = 1 and invalid = 0 and apprvd = 'Yes'"); foreach (var row in data_dt.Rows.ToIEnumerable()) { try { var bllsts = 0; switch (row["bllsts"].ToString().Trim().ToUpper()) { case "UNBILLED": bllsts = 1; break; case "NON-BILLABLE": bllsts = 2; break; case "BILLED": bllsts = 3; break; case "UNBILLABLE COST CODE": bllsts = 2; break; default: throw new SysconException("Invalid Billing Status ({0}) for jobcst record {1}", row["bllsts"], row["recnum"]); } mb7_con.ExecuteNonQuery("update jobcst set bllsts = {0} where recnum = {1}", bllsts, row["recnum"]); auditlog("Updating Billing Status", Convert.ToInt64(row["recnum"])); } catch (Exception ex) { import_errors = true; Env.Log("Error updating Jobcost {2}: {0}\r\n{1}", ex.Message, ex.StackTrace, row["recnum"]); } } // update billing overrides data_dt = excel_con.GetDataTable("Billing Overrides", "select recnum, bllamt from ChangeSummary where mbllovrrde = 1 and invalid = 0 and apprvd = 'Yes'"); foreach (var row in data_dt.Rows.ToIEnumerable()) { try { mb7_con.ExecuteNonQuery("update jobcst set ovrrde = 1, blgamt = {0} where recnum = {1}", row["bllamt"], row["recnum"]); auditlog("updated billing amount", Convert.ToInt64(row["recnum"])); } catch (Exception ex) { import_errors = true; Env.Log("Error updating Jobcst {2}: {0}\r\n{1}", ex.Message, ex.StackTrace, row["recnum"]); } } // update cost codes data_dt = excel_con.GetDataTable("Cost Codes", "select recnum, cstcde from ChangeSummary where mcstcde = 1 and invalid = 0 and apprvd = 'Yes'"); foreach (var row in data_dt.Rows.ToIEnumerable()) { try { mb7_con.ExecuteNonQuery("update jobcst set cstcde = {0} where recnum = {1}", row["cstcde"], row["recnum"]); auditlog("updated cost code", Convert.ToInt64(row["recnum"])); } catch (Exception ex) { import_errors = true; Env.Log("Error updating Jobcst {0}: {1}\r\n{2}", row["recnum"], ex.Message, ex.StackTrace); } } // update notes data_dt = excel_con.GetDataTable("Notes", "select recnum, newntes from ChangeSummary where mnotes = 1 and invalid = 0 and apprvd = 'Yes'"); foreach (var row in data_dt.Rows.ToIEnumerable()) { try { var new_ntetxt = row["newntes"].ToString().Trim(); var old_ntetxt = mb7_con.GetScalar<string>("select ntetxt from jobcst where recnum = {0}", row["recnum"]); new_ntetxt = new_ntetxt.Replace("\r\n", new string(new char[] { (char)124 })); new_ntetxt += new string(new char[] { (char)124 }); var ntetxt = new_ntetxt + old_ntetxt; mb7_con.ExecuteNonQuery("update jobcst set ntetxt = {0} where recnum = {1}", ntetxt.FoxproQuote(), row["recnum"]); auditlog("Updated Notes", Convert.ToInt64(row["recnum"])); } catch (Exception ex) { import_errors = true; Env.Log("Error updating Jobcst {2}: {0}\r\n{1}", ex.Message, ex.StackTrace, row["recnum"]); } } // update partial billings - this must happen last so that any other changes are copied to the new record correctly data_dt = excel_con.GetDataTable("Partial Billings", "select recnum, originalbllqty, bllqty from ChangeSummary where mbllhours = 1 and invalid = 0 and apprvd = 'Yes'"); foreach (var row in data_dt.Rows.ToIEnumerable()) { try { // as an extra-check so this doesn't happen twice because that would be detrimental, make sure // that the original billing quantity matches that that is in SMB currently var smb_bllqty = mb7_con.GetScalar<decimal>("select blgqty from jobcst where recnum = {0}", row["recnum"]); var orig_bllqty = Convert.ToDecimal(row["originalbllqty"]); if (smb_bllqty != orig_bllqty) { throw new SysconException("SMB billing quantity ({0}) does not match original billing quantity ({1})", smb_bllqty, orig_bllqty); } // create a new jobcst record with the difference var jobcst_row = mb7_con.GetDataTable("Job Cost", "select * from jobcst where recnum = {0}", row["recnum"]).Rows[0]; jobcst_row["cstamt"] = 0.0m; jobcst_row["payrec"] = 0; jobcst_row["csthrs"] = 0; jobcst_row["paytyp"] = 0; jobcst_row["blgqty"] = orig_bllqty - Convert.ToDecimal(row["bllqty"]); jobcst_row["srcnum"] = Env.GetConfigVar<int>("NewJobcostSource", 31, true); jobcst_row["usrnme"] = jobcst_row["usrnme"].ToString().Trim() + "-Import"; jobcst_row["ntetxt"] = string.Format("{0}: Split from original billing record #{1}", DateTime.Now, row["recnum"]); jobcst_row["recnum"] = mb7_con.GetScalar<long>("select max(recnum) + 1 from jobcst"); // jobcst_row["ovrrde"] = 1; // insert the record var sql = jobcst_row.FoxproInsertString("jobcst"); mb7_con.ExecuteNonQuery(sql); auditlog(string.Format("Split from {0}", row["recnum"]), Convert.ToInt64(jobcst_row["recnum"])); // update the billing quantity mb7_con.ExecuteNonQuery("update jobcst set blgqty = {0}, ntetxt = {2} + ntetxt where recnum = {1}", row["bllqty"], row["recnum"], string.Format("{0} - Partial Billing, new record (#{1}) added{2}", DateTime.Now, jobcst_row["recnum"], (char)124).FoxproQuote()); auditlog("Set to partial billing", Convert.ToInt64(row["recnum"])); } catch (Exception ex) { import_errors = true; Env.Log("Error updating Jobcst {2}: {0}\r\n{1}", ex.Message, ex.StackTrace, row["recnum"]); } } if (import_errors) { throw new SysconException("Error Importing Data."); } MessageBox.Show("File imported successfully.", "Success", MessageBoxButtons.OK); } catch (Exception ex) { MessageBox.Show("Error updating SMB data, see logfile for details"); Env.Log(string.Format("Error updating SMB data: {0}\r\n{1}", ex.Message, ex.StackTrace)); } } } } }
// Runtime Analysis: // A = COUNT(*) in actrec // C = COUNT(*) in clnnum // J = COUNT(*) in jobtyp // E = COUNT(*) in employ // N = count of records in initialJobList, or 1 if initialJobList is null private void MultiJobSelector_Load(object sender, EventArgs e) { try { using (var con = Connections.GetOLEDBConnection()) { using (var joblist = con.GetTempDBF()) { if (initialJobList != null) { // Runtime: O(N*Log(N)) // specifying that recnum is unique means it is indexed, which gives us better join times con.ExecuteNonQuery("create table {0} (recnum n(10,0) not null unique)", joblist); foreach (var recnum in initialJobList) { con.ExecuteNonQuery("insert into {0} (recnum) values ({1})", joblist, recnum); } } // Runtime: O(A+A*Log(R)+A*Log(J)+A*Log(E)) var sql = string.Format( "select actrec.recnum as JobNumber, jobnme as JobName, jobtyp.typnme as JobType, actrec.status as JobStatus" + ", clnnum as ClientNumber, reccln.shtnme as ClientName" + ", alltrim(employ.fullst) as Supervisor, actrec.contct as SiteContact" + " from actrec" + " left join reccln on clnnum = reccln.recnum" + " left join jobtyp on actrec.jobtyp = jobtyp.recnum" + " left join employ on actrec.sprvsr = employ.recnum"); // Runtime: O(A*Log(N)) sql += initialJobList != null ? string.Format(" join {0} ijoblst on actrec.recnum = ijoblst.recnum", joblist) : ""; // Runtime: O(N) datalines_dt = con.GetDataTable("Job List", sql); datalines_dt = datalines_dt.ToList<DataLine>().ToDataTable("datalines"); current_dt = datalines_dt; // Total Runtime: O(N*Log(N) + A + A*Log(R) + A*Log(J) + A*Log(E) + A*Log(N) + N) // we know that A > N, so we can drop the N*Log(N) term // O(MAX(A*Log(R)+A*Log(J)+A*Log(E)+A*Log(N))) - simplify to dominate term without constants // O(A*MAX(Log(R),Log(J),Log(E),Log(N))) - simplify to dominate term // O(A*Log(MAX(R,J,E,N)) } // load the project supervisors var supervisors_dt = con.GetDataTable("Supervisors", "select distinct employ.recnum, employ.fullst from actrec join employ on actrec.sprvsr = employ.recnum order by employ.fullst asc"); cmbSupervisors.DataSource = new string [] { "*Any*" }.Concat( (from s in supervisors_dt.Rows.ToIEnumerable() select s["fullst"].ToString().Trim())).ToArray(); cmbSupervisors.SelectedIndex = 0; } } catch (Exception ex) { Env.Log("{0}\r\n{1}", ex.Message, ex.StackTrace); MessageBox.Show("Error Loading Job List Form", "Error", MessageBoxButtons.OK); } #if false // Runtime: O(A+A*Log(R)+A*Log(J)+A*Log(E)) datalines_dt = Connections.Connection.GetDataTable("datalines" , "select actrec.recnum as JobNumber, jobnme as JobName, jobtyp.typnme as JobType, actrec.status as JobStatus" + ", clnnum as ClientNumber, reccln.shtnme as ClientName" + ", alltrim(employ.fstnme) + ' ' + alltrim(employ.lstnme) as Supervisor, actrec.contct as SiteContact" + " from actrec" + " left join reccln on clnnum = reccln.recnum" + " left join jobtyp on actrec.jobtyp = jobtyp.recnum" + " left join employ on actrec.sprvsr = employ.recnum"); var progress = new ProgressDialog(datalines_dt.Rows.Count + 1); progress.Text = "Getting Job List"; if (initial_job_filter != null) { progress.Show(); } // Runtime: O(A) // get the correct types, and make sure all columns exist var datalines = datalines_dt.ToList<DataLine>(); datalines_dt = datalines.ToDataTable("datalines"); var jobs = (from j in smbtable.GetAll<actrec>() where initial_job_filter(j) select j.recnum).ToArray(); progress.Tick(); if (initial_job_filter != null) { progress.Text = "Filtering Job List"; // Runtime: O(AN) datalines_dt = datalines_dt.FilterRows(row => { progress.Tick(); return jobs.Contains(Convert.ToInt64(row["JobNumber"])); // return true; }); } current_dt = datalines_dt; progress.Close(); // Total Runtime: O(A + A*Log(R) + A*Log(J) + A*Log(E) + A + AN) // O(A*MAX(Log(R),Log(J),Log(E),N)) - Simplify to dominate term // O(AN) #endif this.chkStatus1.Checked = Env.GetConfigVar("mjselect_chkStatus1", true, true); this.chkStatus2.Checked = Env.GetConfigVar("mjselect_chkStatus2", false, true); this.chkStatus3.Checked = Env.GetConfigVar("mjselect_chkStatus3", true, true); this.chkStatus4.Checked = Env.GetConfigVar("mjselect_chkStatus4", true, true); this.chkStatus5.Checked = Env.GetConfigVar("mjselect_chkStatus5", true, true); this.chkStatus6.Checked = Env.GetConfigVar("mjselect_chkStatus6", true, true); DoFilter(); this.txtFilter.KeyPress += new KeyPressEventHandler(txtFilter_KeyPress); this.chkStatus1.CheckedChanged += new EventHandler(chkStatus_CheckedChanged); this.chkStatus2.CheckedChanged += chkStatus_CheckedChanged; this.chkStatus3.CheckedChanged += chkStatus_CheckedChanged; this.chkStatus4.CheckedChanged += chkStatus_CheckedChanged; this.chkStatus5.CheckedChanged += chkStatus_CheckedChanged; this.chkStatus6.CheckedChanged += chkStatus_CheckedChanged; }
public static IEnumerable<IJob> GetJobs() { return Cache.CacheResult(() => { var count = Connections.GetScalar<int>("select count(*) from actrec"); var progress = new ProgressDialog(count, "Selecting Job List"); progress.Show(); var result = GetJobs(jobNumber => { progress.Tick(); return true; }); progress.Close(); return result; }, "AllJobs"); }