procedure GetBookingQtyRemaining(tcSalespoint as string, tcOperator as string, ; tcReturnType as string, tcDCIList as string, ttDateTime as datetime,; tcCheckType as string, tcCheckCat as string) as string; helpstring "Given an XML(ish) list of items, return qty available left for booking" local lcRetVal, lvRetVal, llCheckType, llCheckCat, ltBOD, ltEOD, lcTypeCond, lcSQLReturn local lcDCIList, lnBegin, lnEnd, lcDCI, lnI, lnHour, lnMin, lcAMPM, ltStartTime, ltEndTime local lcWhereCond, lnLimit, lnQtyBooked, lnRemaining with this .write_log('Entering method...', program(), '1') if vartype(tcSalespoint)<>'C' or vartype(tcOperator)<>'C' or vartype(tcReturnType)<>'C' or; vartype(tcDCIList)<>'C' or vartype(ttDateTime)<>'T' lcRetVal='100-Parameters: tcSalesPoint C12, tcOperator C6, tcReturnType C3, '+; 'tcDCIList (XML) C??, ttDateTime T8, [tcCheckType C1], [tcCheckCat C1]' .write_log('Returning: '+lcRetVal, program(), '2') return .RetValToSTR(lcRetVal) endif if !inlist(tcReturnType,'STR','ADO','XML','XM2') lcRetVal='100-Parameters: tcReturnType must be STR, ADO, XML or XM2' .write_log('Returning: '+lcRetVal, program(), '2') return .RetValToSTR(lcRetVal) endif if vartype(tcCheckType)<>'C' tcCheckType='Y' endif if vartype(tcCheckCat)<>'C' tcCheckCat ='Y' endif llCheckType = (tcCheckType $ ".T./T/TRUE/Y/YES/1") llCheckCat = (tcCheckCat $ ".T./T/TRUE/Y/YES/1") .cCurrentSalesPoint=tcSalespoint .cCurrentOperator=tcOperator .write_log('llCheckType: '+transform(llCheckType), program(), '4') .write_log('llCheckCat: '+transform(llCheckCat), program(), '4') create cursor csrRetCursor (DCI C(30), start_time t, end_time t, limit I, QTY_BOOKED I, QTY_REM I) &&STEP 1 - gather all applicable max4sale restrictions for the given day from SQL Server (fewer round trips) ltBOD=dtot(ttod(ttDateTime)) &&beginning of day ltEOD=dtot(ttod(ttDateTime)+1)-1 &&end of day do case case llCheckType=.t. and llCheckCat=.t. lcTypeCond='type between 2 and 3' case llCheckCat=.t. lcTypeCond='type=2' case llCheckType=.t. lcTypeCond='type=3' otherwise lcTypeCond='0=1' endcase text to lcSQL textmerge noshow select lessontype, lsn_cat, start_time, end_time, max_sale, type, id from dbo.max4sale where start_time < <<.VFP2SQL(ltEOD)>> and end_time > <<.VFP2SQL(ltBOD)>> and <<lcTypeCond>> ENDTEXT lcSQLReturn=.mysqlexec(lcSQL, 'csrMax4Sale', program()) if !lcSQLReturn=='OK' lcRetVal='400-'+lcSQLReturn .write_log(lcRetVal, program(), 'E') .write_log('Returning: '+lcRetVal, program(), '2') return .RetValToSTR(lcRetVal) endif .write_log(transform(reccount('csrMax4Sale'))+' restrictions found in Max4Sale that may be applicable', program(), '4') &&STEP 2 - loop through each DCI requested... lcDCIList=tcDCIList &&make a copy to cut up... lnBegin=at('<DCI>',lcDCIList) do while lnBegin>0 lnEnd=at('</DCI>',lcDCIList) if lnBegin=0 or lnEnd=0 exit &&tag not found? endif lcDCI=padr(substr(lcDCIList, lnBegin+5, lnEnd-lnBegin-5),30) lcDCIList=substr(lcDCIList, lnEnd+6) &&STEP 3 - get start times, lessontype and category information for each DCI text to lcSQL textmerge noshow select l.startime1, l.startime2, l.startime3, l.startime4, l.startime5, l.startime6, l.startime7, l.startime8, l.startime9, l.startime10, l.span, l.lessontype, isnull(t.lsn_cat, '*') as lsn_cat from dbo.b_lessns l join dbo.b_lsntyp t on l.lessontype=t.type_id where l.department=<<.VFP2SQL(substr(lcDCI,1,10))>> and l.category =<<.VFP2SQL(substr(lcDCI,11,10))>> and l.item =<<.VFP2SQL(substr(lcDCI,21,10))>> ENDTEXT lcSQLReturn=.mysqlexec(lcSQL, 'csrDCIInfo', program()) if !lcSQLReturn=='OK' lcRetVal='400-'+lcSQLReturn .write_log(lcRetVal, program(), 'E') .write_log('Returning: '+lcRetVal, program(), '2') return .RetValToSTR(lcRetVal) endif &&if we didn't find the lesson type and lesson category for this DCI, go on to the next one... if reccount('csrDCIInfo')=0 .write_log('No lesson type and category information found for: '+lcDCI+' skipping...', program(), '4') loop endif &&STEP 4 - loop through each start time for this DCI for lnI=1 to 10 &&loop through each possible start time for this DCI lcStartTime=evaluate('csrDCIInfo.startime'+transform(lnI)) if empty(lcStartTime) &&if it ain't filled in, don't process it... loop endif lnHour=val(substr(lcStartTime,1,at(':',lcStartTime)-1)) lcAMPM=iif(at('AM',lcStartTime)>0, 'AM', 'PM') do case case lnHour=12 and lcAMPM='AM' lnHour=0 case lnHour<>12 and lcAMPM='PM' lnHour=lnHour+12 endcase lnMin =val(substr(lcStartTime,at(':',lcStartTime)+1)) ltStartTime=ltBOD + (lnHour*60*60) + (lnMin*60) ltEndTime=ltStartTime + (csrDCIInfo.span*60) &&STEP 5 - gather applicable restrictions for this start time for this DCI do case case llCheckType=.t. and llCheckCat=.t. lcWhereCond="((type=2 and lsn_cat="+.VFP2SQL(csrDCIInfo.lsn_cat)+; ") or (type=3 and lessontype="+.VFP2SQL(csrDCIInfo.lessontype)+"))" case llCheckCat=.t. lcWhereCond="type=2 and lsn_cat="+.VFP2SQL(csrDCIInfo.lsn_cat) otherwise lcWhereCond="type=3 and lessontype="+.VFP2SQL(csrDCIInfo.lessontype) endcase select *; from csrMax4Sale; into cursor csrDCILimits NOFILTER; where start_time < ltEndTime and end_time > ltStartTime and &lcWhereCond &&if we didn't find the lesson type and lesson category for this DCI, go on to the next one... if reccount('csrDCILimits')=0 .write_log('No Max4Sale limits found for: '+lcDCI+; ' for: '+this.FormatDateTimeShort(ltStartTime, .t.)+' thru '+this.FormatDateTimeShort(ltEndTime, .t.)+' skipping...', program(), '4') loop endif .write_log(transform(reccount('csrDCILimits'))+' Restrictions found for: '+lcDCI, program(), '4') if .nVerbosityLevel>4 &&.write_log() assmebles string first - can be very slow .write_log(.xml_dbf2str('CSRDCILIMITS',-1), program(), '5') endif &&STEP 6 - loop through each restriction for this start time for this DCI and add up bookings lnLimit = -999999999 lnQtyBooked = -999999999 lnRemaining = 9999999999999 select csrDCILimits go top scan if type=2 &&lsn_cat restriction text to lcSQLStmt textmerge noshow select count(*) as Kount from dbo.b_sched where start_time < <<.VFP2SQL(min(ltEndTime,csrDCILimits.end_time))>> and end_time > <<.VFP2SQL(max(ltStartTime,csrDCILimits.start_time))>> and lsn_cat = <<.VFP2SQL(csrDCILimits.lsn_cat)>> and is_pod=0 and layer <> 7 ENDTEXT else &&lessontype restriction text to lcSQLStmt textmerge noshow select count(*) as Kount from dbo.b_sched where start_time < <<.VFP2SQL(min(ltEndTime,csrDCILimits.end_time))>> and end_time > <<.VFP2SQL(max(ltStartTime,csrDCILimits.start_time))>> and lessontype = <<.VFP2SQL(csrDCILimits.lessontype)>> and is_pod=0 and layer <> 7 ENDTEXT endif lcSQLReturn=.mysqlexec(lcSQLStmt, 'csrKount', program()) if !lcSQLReturn=='OK' lcRetVal='400-Line: '+transform(lineno())+' '+lcSQLReturn .write_log(lcRetVal, program(), 'E') .write_log('Returning: '+lcRetVal, program(), '2') return .RetValToSTR(lcRetVal) endif .write_log(transform(csrKount.Kount)+' lessons matching '+; iif(csrDCILimits.type=2,'Category','Lesson Type')+' restriction found for '+; this.FormatDateTimeShort(ltStartTime, .t.)+' thru '+this.FormatDateTimeShort(ltEndTime, .t.), program(), '4') if csrDCILimits.max_sale-csrKount.Kount < lnRemaining &&we have a new winner lnLimit = csrDCILimits.max_sale lnQtyBooked = csrKount.Kount lnRemaining = lnLimit-lnQtyBooked endif select csrDCILimits endscan insert into csrRetCursor; (DCI, start_time, end_time, limit, QTY_BOOKED, QTY_REM); values; (lcDCI, ltStartTime, ltEndTime, lnLimit, lnQtyBooked, lnRemaining) endfor lnBegin=at('<DCI>',lcDCIList) enddo &&process each DCI select csrRetCursor do case case tcReturnType=='STR' if eof() lvRetVal='1-DONE' else lvRetVal='0-'+.rec2string(.t.) endif case tcReturnType=='ADO' lvRetVal=.ado_dbf2rs(alias(), -1) case tcReturnType=='XM2' lvRetVal='0-'+.xm2_dbf2str(alias(), -1) otherwise lvRetVal='0-'+.xml_dbf2str(alias(), -1) endcase if used('CSRMAX4SALE') use in csrMax4Sale endif if used('csrDCIInfo') use in csrDCIInfo endif if used('CSRKOUNT') use in csrKount endif if vartype(lvRetVal)='O' .write_log('Returning: {ADO Recordset}', program(), '2') else .write_log('Returning: '+lvRetVal, program(), '2') endif return .RetValToSTR(lvRetVal) endwith endprocYou see, it's a big procedure with some complex logic. This is not the most complex method in the VFP class I'm working on but moderately complex. There are several methods which are 3/4 times as complex as this one.