I added some attributes and functions in "OUR" One2Many Form Demo Project. I sincerely believe in using the word "OUR", because it's not only me who is learning HMG through the project, "WE", the learners of HMG are learning through this project.
Add, Delete, Save, Cancel functions are added. One check is added to check any change is made or not.
Please advise as before to improve the project.
One thing more. As it becomes bigger, next time I shall upload zip file (Is zip allowd?, .prg is not allowed. I tried it)
Thank you Rathinagiri for helping so much. Hi Alex and Swapan, thank you all. And thank you CCH, you always kept my focus on HMG
With best regards.
Code: Select all
#include "dbstruct.ch"
#include "minigui.ch"
static aGrid := {}, aCustSource := {}, aCustDisp := {}, ;
aItemSource := {}, aItemDisp := {}, aItemRate := {}, ;
lChanged := .f., lAddMode := .f.
Function Main
local i, cb
SetProg()
CreateTable()
select sale
set order to tag invno
go top
CreateLookup()
DEFINE WINDOW Form_1 ;
AT 0,0 ;
WIDTH 640 ;
HEIGHT 430 ;
TITLE "One To Many Form (Ver 1.0)" ;
MAIN ;
on init RefreshWin()
@ 10, 10 label lblInvno value "Invoice No.:"
@ 10, 100 textbox txtInvno ;
readonly
@ 10, 300 label lblInvdt value "Invoice Dt.:"
@ 10, 400 datepicker dpkInvdt ;
on change ValChanged()
@ 40, 10 label lblCustcd value "Customer:"
@ 40, 100 COMBOBOX cboCustcd ;
items aCustDisp ;
width 200 ;
on change ValChanged()
@ 70,10 GRID grdSaledtl ;
WIDTH 550 ;
HEIGHT 250 ;
HEADERS {'Item', 'Rate', 'Qty', 'Amt'} ;
WIDTHS {200,100,100,100} ;
COLUMNCONTROLS { {'COMBOBOX', aItemDisp}, ;
{'TEXTBOX', 'NUMERIC', '999999.99'}, ;
{'TEXTBOX', 'NUMERIC', '999999'}, ;
{'TEXTBOX', 'NUMERIC', '99999999.99'}} ;
edit ;
justify {0,1,1,1};
on lostfocus calcamt();
on change ValChanged()
@ 320, 10 label lblMesg1 value "(Ins: Add New, Del: Delete)" width 200
@ 330, 300 label lblTotamt value "Total:"
@ 330, 400 textbox txtTotamt ;
readonly ;
numeric ;
inputmask "9999999.99"
@ 360, 10 button cmdPrev caption "&Previous" ;
action MovePrev()
@ 360, 110 button cmdNext caption "&Next" ;
action MoveNext()
@ 360, 210 button cmdAdd caption "&Add" ;
action AddRec()
@ 360, 310 button cmdDelete caption "&Delete" ;
action DeleteRec()
@ 360, 410 button cmdSave caption "&Save" ;
action SaveRec()
@ 360, 510 button cmdCancel caption "&Cancel" ;
action CancelRec()
END WINDOW
on key DELETE of form_1 action dodel()
on key INSERT of form_1 action doins()
CENTER WINDOW Form_1
ACTIVATE WINDOW Form_1
Return
FUNCTION CreateLookup()
local i
aItemSource := {}
aItemDisp := {}
aItemRate := {}
aCustSource := {}
aCustDisp := {}
select item
set order to tag itemnm
do while !eof()
aadd(aItemSource, item->itemcd)
aadd(aItemDisp, item->itemnm)
aadd(aItemRate, item->rate)
skip
enddo
select cust
set order to tag custnm
do while !eof()
aadd(aCustSource, cust->custcd)
aadd(aCustDisp, cust->custnm)
skip
enddo
return nil
FUNCTION RefreshWin()
if lAddMode
select sale
go bottom
form_1.txtInvno.value := str(val(sale->invno)+1, 10)
form_1.dpkInvdt.value := date()
form_1.cboCustcd.value := 0
form_1.txtTotamt.value := 0.00
aGrid := {}
form_1.grdSaledtl.DeleteAllItems()
else
form_1.txtInvno.value := sale->invno
form_1.dpkInvdt.value := sale->invdt
form_1.cboCustcd.value := ascan(aCustSource, {|x| x == sale->custcd})
form_1.txtTotamt.value := sale->totamt
aGrid := {}
select saledtl
set order to tag invno
locate for invno = sale->invno
do while !eof()
aadd(aGrid, {ascan(aItemSource, {|x| x == saledtl->itemcd}), ;
saledtl->rate, saledtl->qty, saledtl->rate*saledtl->qty})
continue
enddo
form_1.grdSaledtl.DeleteAllItems()
for i = 1 to len(aGrid)
form_1.grdSaledtl.additem(aGrid[i])
next
endif
return nil
PROCEDURE CalcAmt()
local i, nIctr, aTemp := {}, mTotAmt := 0.00
// lChange := .t.
i := form_1.grdSaledtl.value
nIctr := form_1.grdSaledtl.cell(i, 1)
aTemp := form_1.grdSaledtl.item(i)
if i < 1
return
endif
aTemp[2] := iif(nIctr>0 .and. nIctr<=len(aItemRate), aItemRate[nIctr], 0.00)
aTemp[4] := aTemp[2]*aTemp[3]
form_1.grdSaledtl.item(i) := aTemp
for i = 1 to form_1.grdSaledtl.Itemcount
mTotAmt += form_1.grdSaledtl.cell(i, 4)
next
form_1.txtTotamt.value := mTotAmt
return
PROCEDURE MovePrev()
if IsChanged()
return
endif
select sale
if !bof()
skip -1
endif
if bof()
go top
endif
RefreshWin()
PROCEDURE MoveNext()
if IsChanged()
return
endif
select sale
if !eof()
skip
endif
if eof()
go bottom
endif
RefreshWin()
FUNCTION ValChanged()
lChanged := .t.
return nil
FUNCTION IsChanged()
if lAddMode .or. lChanged
msgbox("Record Changed. Please Save or Cancel."); return .t.
endif
return .f.
FUNCTION AddRec()
if IsChanged()
return
endif
lAddMode := .t.
lChanged := .t.
RefreshWin()
return nil
FUNCTION DeleteRec()
if IsChanged()
return
endif
if !MsgYesNo("Do you really want to delete?")
return
endif
select sale
if eof()
msgbox("Cannot Delete"); return
endif
select saledtl
delete all for invno = sale->invno
select sale
delete
skip
if eof()
go bottom
endif
RefreshWin()
FUNCTION SaveRec()
local i
select sale
if eof()
msgbox("Please Add and then Save...");return
endif
if empty(form_1.dpkInvdt.value)
msgbox("Please specify Invoice date!"); form_1.dpkInvdt.setfocus(); return
endif
if empty(form_1.cboCustcd.value)
msgbox("Please specify Customer!"); form_1.cboCustcd.setfocus(); return
endif
if empty(form_1.grdSaledtl.itemcount)
msgbox("Invoice must have Items!"); form_1.grdSaledtl.setfocus();return
endif
for i := 1 to form_1.grdSaledtl.itemcount
do case
case empty(form_1.grdSaledtl.cell(i, 1))
msgbox("Please specify Item!");return
case empty(form_1.grdSaledtl.cell(i, 2))
msgbox("Blank Rate not allowed!");return
case empty(form_1.grdSaledtl.cell(i, 3))
msgbox("Blank Qty not allowed!");return
endcase
next
select sale
if lAddMode
append blank
endif
sale->invno := form_1.txtInvno.value
sale->invdt := form_1.dpkInvdt.value
sale->custcd := aCustSource[form_1.cboCustcd.value]
sale->totamt := form_1.txtTotamt.value
select saledtl
if !lAddmode
delete all for invno = sale->invno
endif
for i := 1 to form_1.grdSaledtl.itemcount
append blank
saledtl->invno := sale->invno
saledtl->itemcd := aItemSource[form_1.grdSaledtl.cell(i, 1)]
saledtl->rate := form_1.grdSaledtl.cell(i, 2)
saledtl->qty := form_1.grdSaledtl.cell(i, 3)
next
lAddMode := lChanged := .f.
RefreshWin()
return nil
FUNCTION CancelRec()
lAddMode := lChanged := .f.
RefreshWin()
return nil
Function SetProg()
set talk off
set dele on
set date brit
set cent on
set epoch to 1950
SET BROWSESYNC ON
SET NAVIGATION EXTENDED
SET INTERACTIVECLOSE QUERY MAIN
set font to "Arial", 09
REQUEST DBFCDX , DBFFPT
RDDSETDEFAULT( "DBFCDX" )
return nil
FUNCTION CreateTable()
local aDbf := {}
if !file("item.dbf")
aDbf := {}
aadd(adbf, {"itemcd", "c", 10, 0})
aadd(adbf, {"itemnm", "c", 20, 0})
aadd(adbf, {"rate", "n", 8, 2})
dbcreate("item", adbf)
use item
append blank
replace itemcd with "COMP", itemnm with "Computer", rate with 20000.00
append blank
replace itemcd with "CD", itemnm with "Compact Disk", rate with 10.00
append blank
replace itemcd with "OPM", itemnm with "Optical Mouse", rate with 400.00
use
endif
if !file("cust.dbf")
aDbf := {}
aadd(adbf, {"custcd", "c", 10, 0})
aadd(adbf, {"custnm", "c", 20, 0})
dbcreate("cust", adbf)
use cust
append blank
REPLACE CUSTCD WITH "CUST1", CUSTNM WITH "Customer One"
append blank
REPLACE CUSTCD WITH "CUST2", CUSTNM WITH "Customer Two"
append blank
REPLACE CUSTCD WITH "CUST3", CUSTNM WITH "Customer Three"
use
endif
if !file("sale.dbf")
aDbf := {}
aadd(adbf, {"invno", "c", 10, 0})
aadd(adbf, {"invdt", "d", 8, 0})
aadd(adbf, {"custcd", "c", 10, 0})
aadd(adbf, {"totamt", "n", 10, 2})
dbcreate("sale", adbf)
use sale
append blank
replace invno with str(1, 10), invdt with date(), custcd with "CUST1", totamt with 40200.00
append blank
replace invno with str(2, 10), invdt with date(), custcd with "CUST2", totamt with 420
use
endif
if !file("saledtl.dbf")
aDbf := {}
aadd(adbf, {"invno", "c", 10, 0})
aadd(adbf, {"itemcd", "c", 10, 0})
aadd(adbf, {"rate", "n", 8, 2})
aadd(adbf, {"qty", "n", 6, 0})
dbcreate("saledtl", adbf)
use saledtl
append blank
replace invno with str(1, 10), itemcd with "COMP", rate with 20000.00, qty with 2
append blank
replace invno with str(1, 10), itemcd with "CD", rate with 10.00, qty with 20
append blank
replace invno with str(2, 10), itemcd with "CD", rate with 10.00, qty with 5
append blank
replace invno with str(2, 10), itemcd with "OPM", rate with 400.00, qty with 1
use
endif
close databases
use item new
use cust new
use sale new
use saledtl new
select item
index on itemcd tag itemcd
index on upper(itemnm) tag itemnm
select cust
index on custcd tag custcd
index on upper(custnm) tag custnm
select sale
index on invno tag invno
index on invdt tag invdt
index on custcd tag custcd
select saledtl
index on invno tag invno
index on itemcd tag intemcd
return nil
function dodel
local lineno := form_1.grdsaledtl.value
if lineno > 0
form_1.grdsaledtl.deleteitem(lineno)
if lineno > 1
form_1.grdsaledtl.value := lineno - 1
else
if form_1.grdsaledtl.itemcount > 0
form_1.grdsaledtl.value := 1
endif
endif
endif
calcamt()
return nil
function doins
//if form_1.grdSaledtl.cell(form_1.grdsaledtl.itemcount, 4) > 0.0
// form_1.grdsaledtl.additem({1,aitemrate[1],0,0.00})
//endif
form_1.grdsaledtl.additem({0,0.00,0,0.00})
form_1.grdSaledtl.value := form_1.grdsaledtl.itemcount
return nil