全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:1040
推到 Plurk!
推到 Facebook!

关于一个还款功能的实现

答題得分者是:malanlk
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-10-13 17:00:34 IP:222.184.xxx.xxx 未訂閱
功能如下: 重要数据库字段:姓名 应收金额,实收金额。(实收金额小于应收金额就视作欠费记录) 1。输入病人姓名后按回车键显示欠款总金额(这一点估计我自己会做) 2。输入还款金额,下面有可能出现几种情况:(主要是这一步不懂做) (1)欠费记录只有一条(也就是说病人只欠了一次费),还款金额等于欠费金额 (2)欠费记录有N条(也就是说病人欠了N次费),还款金额等于欠费金额 (3)欠费记录有N条(也就是说病人欠了N次费),还款金额不等于欠费金额,也就是说只还一部份欠款,这是最难的一点了,还款金额如何分次记录到数据中。 上面所说的一切,包括查询和还款,其实都是在收费记录库中操作中的,不另外有欠费专门所有的数据表。
------
我的编程起步于ktop,我将永远支持ktop
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-10-13 17:41:38 IP:222.184.xxx.xxx 未訂閱
我把我的思路一步一步写出来: 下面是欠费查询功能: ADOQUery1.Close; ADOQUery1.SQL.Clear; ADOQUery1.SQL.Add('select 病人id,病人姓名,病人性别,病人年龄 from tb_sf where 应找金额<0'); ADOQUery1.Open; 这上面我还有一个功能未做到,也就是要sum 应找金额 如何selcet 在病人年龄后面,想要执行的代码如下: ADOQUery1.SQL.Add('select 病人id,病人姓名,病人性别,病人年龄 sum (应找金额) from tb_sf where 应找金额<0'); 现在sum (应找金额)加在后面就要出错,即使不出错的话,那个应找金额是个负数,我要求和的结果也是正数
------
我的编程起步于ktop,我将永远支持ktop
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-10-13 19:20:57 IP:203.69.xxx.xxx 未訂閱
你的 "應找金額" 是欄位之ㄧ嗎? 還是你自己編出來的?    應找金額=實收金額-應收金額    'select 病人id,病人姓名,病人性別,病人年齡,sum(應收金額-實收金額) as 欠費金額 from tb_sf where 實收金額-應收金額<0' 這樣試試! 收到欠費後 採用先欠先抵的原則, 逐一扣除即可... 其中要注意的就是 "實收金額" 應視為 "上次已收金額" 收到欠費攤到的金額則是 "本次實收金額", 這樣分的主要原因是可能有好幾次都欠費... 也就是 "上次已收金額" "本次實收金額"=應收金額
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-10-14 07:18:44 IP:222.184.xxx.xxx 未訂閱
应找金额是数据库的栏位之一,不是后来编出来的。 所以我用的是: ('select 病人id,病人姓名,病人性别,病人年龄 sum (应找金额) from tb_sf where 应找金额<0'); 但出现如图错误: 如果把病人ID去掉也不行。 另外前辈所说的还款思路正是我想要的,但小弟思路是懂,但实际操作中如何写代码就无从下手了,前辈能否取例一二? 發表人 - ntjrr 於 2005/10/14 07:22:34
------
我的编程起步于ktop,我将永远支持ktop
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-10-14 09:25:30 IP:203.69.xxx.xxx 未訂閱
('select 病人id,病人姓名,病人性別,病人年齡,sum(-1*應找金額) as 欠費金額 from tb_sf where 應找金額<0 and 病人id=''' patient_id ''' group by 病人id,病人姓名,病人性別,病人年齡') 將 select 出來的資料 放入 StringGrid 內 在 輸入 還款金額(假設是 Edit1) 時, 在 Edit1 的 OnChange Event 中 做攤還的動作
payment := StrToIntDef(Edit1.Text,-1);
if payment>0 then
begin
  for i:=1 to StringGrid.RowCount-1 do
  begin
    if payment>=本項欠費金額 then
    begin
      本項本次還款金額=本項欠費金額
    end
    else
    begin
      本項本次還款金額=payment
    end;
    payment := payment-本項本次還款金額;
    if payment=0 then break;
  end;
end;
發表人 - malanlk 於 2005/10/14 12:36:01
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-10-14 11:53:10 IP:222.184.xxx.xxx 未訂閱
前辈,我上面所说的如图错误,不知道为什么产生,先第一步克服这一关,我才能够得已继续到下一步的过程了。
------
我的编程起步于ktop,我将永远支持ktop
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-10-14 12:50:00 IP:203.69.xxx.xxx 未訂閱
照上面 加 group by 也會出錯嗎?
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-10-15 16:17:44 IP:222.184.xxx.xxx 未訂閱
欠费查询中加上group by 已经成功了。 在还款时所指的payment,我的理解是一个变量,应该是小数点后保留两位的数据(也就是常用的金额了)按您所指就是设两个变量, var i:integer; payment:(这里应设为什么?设为FLOAT好象不行) 另外在还款单元中我不用DBGRID了(在查询时用的,但在这个还款功能窗口不用)是不是我就将for i:=1 to StringGrid.RowCount-1 do 改为for i:=1 to adoquery1.RowCount-1 do
------
我的编程起步于ktop,我将永远支持ktop
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-10-15 22:18:35 IP:222.184.xxx.xxx 未訂閱
我目前已做到的功能如下: 1。在edit1框中填入拼音码后回车选择病人,那么EDIT2框中自动能计算出该病人的累计欠款,部分代码如下: ADOQUery1.Close; ADOQUery1.SQL.Clear; ADOQUery1.SQL.Add('select sum(-1*应找金额) as 欠费金额 from tb_sf where 应找金额<0 '); ADOQUery1.SQL.Add(' and 病人id=:brid');//病人的ID编号为唯一索引 ADOQuery1.Parameters.ParamByName('brid').Value:=strtoint(label4.Caption); ADOQUery1.Open; edit2.Text:=ADOQuery1.Fields[0].AsString; 我下一步想要做的,就是在EDIT3中填入还款的金额,按确定键实现还款。
------
我的编程起步于ktop,我将永远支持ktop
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-10-16 01:25:12 IP:61.219.xxx.xxx 未訂閱
ADOQuery1.Close;
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('select count(*) as 筆數,sum(-1*應找金額) as 欠費金額 from tb_sf where 應找金額<0 and 病人id=''' patient_id '''');
ADOQuery1.Open;
... 取出數量及欠費總金額
iTotalRecord := ADOQuery1.FieldByName('筆數').AsInteger;
... 依數量設定 StringGrid 列數
StringGrid1.RowCount := iTotalRecord 1;
ADOQuery1.Close;
ADOQuery1.SQL.Clear;
ADOQuery1.SQL.Add('select 收費日期,應收金額,(-1*應找金額) as 欠費金額 from tb_sf where 應找金額<0 and 病人id=''' patient_id '''');
ADOQuery1.Open;
i:=1;
while not ADOQuery1.Eof do
begin
  StringGrid1.Cells[0,i] := ADOQuery1.FieldByName('收費日期').AsString;
  StringGrid1.Cells[1,i] := ADOQuery1.FieldByName('應收金額').AsString;
  StringGrid1.Cells[2,i] := ADOQuery1.FieldByName('欠費金額').AsString;
  ADOQuery1.Next;
  i := i 1;
end;
發表人 - malanlk 於 2005/10/16 01:27:43
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#11 引用回覆 回覆 發表時間:2005-10-16 07:27:49 IP:222.184.xxx.xxx 未訂閱
前辈,您所说的stringgrid,小弟还没有能掌握相关的知识,不过在查询欠费上我基本上已做出来,我用的是dbgrid 显示查询出的记录的。 我一共做的是两个窗口,一个窗口是欠费统计查询,其中是用DBGRID做显示的,我现在所说的是还款结算窗口,我没有放STRINGGRID,也没有放DBGRID,依小弟的理解,您上面所指点的是欠费查询及显示一块的功能。 我现在关键一点是不懂还款如何摊还,如果依前辈在第五层所指点的还款方法来看,小弟的不理解之处也就是写在第八层中,一个是那个变量的数据类型,一个是我不用DBGRID也不用STRINGGRID时如何做?谢谢!
------
我的编程起步于ktop,我将永远支持ktop
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#12 引用回覆 回覆 發表時間:2005-10-16 17:54:21 IP:222.184.xxx.xxx 未訂閱
在还款执行代码中,有几个重要参数如下:
例如:
查到某个人的欠费记录如下:
应收金额  实收金额  应找金额
20          5        -15
105         0        -105
这个人实际欠费是120元,但他有可能本次还100元
那么就要先还某一个,多余的再往下还款,还款执行后的数据记录变成 
应收金额  实收金额  应找金额
20          20       0
105         85       -20          
發表人 - ntjrr 於 2005/10/16 18:00:51
------
我的编程起步于ktop,我将永远支持ktop
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#13 引用回覆 回覆 發表時間:2005-10-16 18:27:28 IP:61.219.xxx.xxx 未訂閱
vPayment: Double; vItemPay, vPay: Double; sItemNo: String; bComplete: Boolean;    輸入還款金額後按 "確定"     照你的要求直接用 query 逐筆攤掉....  vPayment := StrToFloat(Edit1.Text); ...    
ADOQuery1.Close;
repeat
  ADOQuery1.SQL.Clear;
  ADOQuery1.SQL.Add('select top 1 收費編號,(-1*應找金額) as 欠費金額 from tb_sf where 應找金額<0 and 病人id=''' patient_id ''' order by 收費編號');
  ADOQuery1.Open;
  if not ADOQuery1.Eof do
  begin
    vItemPay := ADOQuery1.FieldByName('欠費金額').AsFloat;
    sItemNo := ADOQuery1.FieldByName('收費編號').AsString;
    ADOQuery1.Close;
    ADOQuery1.SQL.Clear;
    if (vItemPay>vPayment) then
      vPay := vPayment-vItemPay;
    else
      vPay := 0;
    ADOQuery1.SQL.Add('update tb_sf set 應找金額=:vPay where 收費編號=:sItemNo');
    ADOQuery1.Parameters.ParamByName('vPay').Value:= vPay;
    ADOQuery1.Parameters.ParamByName('sItemNo').Value:= sItemNo;
    ADOQuery1.ExecSQL;
    if (vItemPay>vPayment) then
      vPayment := 0
    else
      vPayment := vPayment-vItemPay;
  end
  else
  begin
    bComplete := True;
  end;
until (bComplete or (vPayment<=0));
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#14 引用回覆 回覆 發表時間:2005-10-16 19:36:09 IP:222.184.xxx.xxx 未訂閱
小弟将您的代码根据我的实际情况修改了一下:
var
vPayment: Double;
vItemPay, vPay: Double;
sItemNo: String;
bComplete: Boolean;
begin
if  StrToFloat(Edit3.Text)> StrToFloat(Edit2.Text)  then
showmessage('还款金额不能大于欠费金额!')
else
begin
vPayment := StrToFloat(Edit3.Text);
ADOQuery1.Close;
repeat
  ADOQuery1.SQL.Clear;
  ADOQuery1.SQL.Add('select top 1 票据号,(-1*应找金额) as 欠费金额 from tb_sf where 应找金额<0');
  ADOQUery1.SQL.Add(' and 病人id=:brid');
  ADOQUery1.SQL.Add(' order by 票据号');
ADOQuery1.Parameters.ParamByName('brid').Value:=strtoint(label4.Caption);
  ADOQuery1.Open;
  if not ADOQuery1.Eof  then
  begin
    vItemPay := ADOQuery1.FieldByName('欠费金额').AsFloat;
    sItemNo := ADOQuery1.FieldByName('票据号').AsString;
    ADOQuery1.Close;
    ADOQuery1.SQL.Clear;
    if (vItemPay>vPayment) then
       vPay := vPayment-vItemPay
    else
      vPay := 0;
    ADOQuery1.SQL.Add('update tb_sf set 应找金额=:vPay,where 票据号=:sItemNo');
    ADOQuery1.Parameters.ParamByName('vPay').Value:= vPay;
    ADOQuery1.Parameters.ParamByName('sItemNo').Value:= sItemNo;
    ADOQuery1.ExecSQL;
    if (vItemPay>vPayment) then
      vPayment := 0
    else
      vPayment := vPayment-vItemPay;
  end
  else
  begin
    bComplete := True;
  end;
until (bComplete or (vPayment<=0));    目前测试了一下,所有代码能正常执行,因为这个问题虽然小,但比较复杂,所以我就分次提问如下了:
1。 bComplete 可能一次也执行不到
2。实收金额仍是为0,我想的要是实收金额也要填上
如果本来应收为100 实收为0,那么还款100后,实收也为100,如果还款90,那么实收就为90。
3.如果该病人欠费记录有N笔,那么还款时即使有足够的钱,但还是只会还掉第一笔欠费,其它欠费还不掉。
先处理好这一个,我再测试一下在数种还款可能的情况下的代码执行情况。      
發表人 - ntjrr 於 2005/10/16 19:55:14 發表人 - ntjrr 於 2005/10/16 22:13:51
------
我的编程起步于ktop,我将永远支持ktop
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#15 引用回覆 回覆 發表時間:2005-10-16 22:30:46 IP:61.219.xxx.xxx 未訂閱
如果不小心 輸入金額太多, Payment 就不會<=0 這個 repeat 就永遠停不了...    
vPayment: Double;
vItemPay, vPay, vItemPaid: Double;
sItemNo: String;
bComplete: Boolean;    輸入還款金額後按 "確定"     照你的要求直接用 query 逐筆攤掉.... 
vPayment := StrToFloat(Edit1.Text);
...        ADOQuery1.Close;
repeat
  ADOQuery1.SQL.Clear;
  ADOQuery1.SQL.Add('select top 1 收費編號,實收金額,(-1*應找金額) as 欠費金額 from tb_sf where 應找金額<0 and 病人id=''' patient_id ''' order by 收費編號');
  ADOQuery1.Open;
  if not ADOQuery1.Eof do
  begin
    vItemPay := ADOQuery1.FieldByName('欠費金額').AsFloat;
    vItemPaid := ADOQuery1.FieldByName('實收金額').AsFloat;
    sItemNo := ADOQuery1.FieldByName('收費編號').AsString;
    ADOQuery1.Close;
    ADOQuery1.SQL.Clear;
    if (vItemPay>vPayment) then
    begin
      vPay := vPayment-vItemPay;
      vItemPaid := vItemPaid vPayment; 
    end
    else
    begin
      vItemPaid := vItemPaid vItemPay;
      vPay := 0;
    end;
    ADOQuery1.SQL.Add('update tb_sf set 實收金額=:vItemPaid,應找金額=:vPay where 收費編號=:sItemNo');
    ADOQuery1.Parameters.ParamByName('vPay').Value:= vPay;
    ADOQuery1.Parameters.ParamByName('vItemPaid').Value:= vItemPaid;
    ADOQuery1.Parameters.ParamByName('sItemNo').Value:= sItemNo;
    ADOQuery1.ExecSQL;
    if (vItemPay>vPayment) then
      vPayment := 0
    else
      vPayment := vPayment-vItemPay;
  end
  else
  begin
    bComplete := True;
  end;
until (bComplete or (vPayment<=0));
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#16 引用回覆 回覆 發表時間:2005-10-17 07:32:22 IP:222.184.xxx.xxx 未訂閱
现在初步测试基本成功了,目前发现的问题就是在小数的处理上,有0.0600000001这样的数字产生,我再看一下,估计是float处理上的问题,其它的我再进一步测试 小数上不知道这样用行不行的: strtofloat(Format('%.2f',[ADOQuery1.fieldbyname('金额').AsFloat]));
------
我的编程起步于ktop,我将永远支持ktop
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#17 引用回覆 回覆 發表時間:2005-10-17 12:00:43 IP:222.184.xxx.xxx 未訂閱
我如此改了一下,那么应找余额就不会出现小数上的异常了,不知道这样是否可以? vPay := strtofloat(format('%.2f',[vPayment-vItemPay])); 目前的问题是当这个人欠费两次,也就是有两个不同的票据号时,那么欠费还款时只能还掉第一个欠费,第二个无法生效,我想要的功能是,如果还款的金额还掉第一笔后,还有钱余下来,那么余下来的钱继续还下一笔,直到没有钱余下或者还清所有欠款为止。
------
我的编程起步于ktop,我将永远支持ktop
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#18 引用回覆 回覆 發表時間:2005-10-17 12:43:20 IP:203.69.xxx.xxx 未訂閱
我有用 repeat .... until  bComplete := False; repeat ....
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#19 引用回覆 回覆 發表時間:2005-10-17 18:10:48 IP:222.184.xxx.xxx 未訂閱
bComplete := False; 果然这一句一加就立马生效了,基本上测了几次,没测出什么明显的错误出来,这些代码虽然不长,但小弟基本功不够,里面的层次还理解的不是太清,请问前辈,如果要提示还款成功或者还款不成功,分别写在哪一行比较好,谢谢!
------
我的编程起步于ktop,我将永远支持ktop
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#20 引用回覆 回覆 發表時間:2005-10-17 18:49:02 IP:203.69.xxx.xxx 未訂閱
還款不成功是什麼意思? 基本上只要攤還成功, 就算還款成功吧?    如果是這樣, 那就...    
try
  repeat
  ....
  until ();
  ShowMessage('還款成功');
except
  ShowMessage('還款過程錯誤');
end;
發表人 - malanlk 於 2005/10/17 18:50:04
ntjrr
高階會員


發表:240
回覆:312
積分:110
註冊:2005-04-24

發送簡訊給我
#21 引用回覆 回覆 發表時間:2005-10-17 21:51:47 IP:222.184.xxx.xxx 未訂閱
前辈,我根据您的指教,结合我的程序的实际情况,最终的代码如下: 现在经过初步的测试尚未测出什么问题,我还得仔细测,麻烦前辈先过目一下,我修改后的代码有无不妥之处,谢谢! 
 
var
vPayment: Double;
vItemPay,vItempaid, vPay: Double;
sItemNo: String;
bComplete: Boolean;    begin
if edit3.Text='' then
showmessage('还款金额不能为空白!')
else
if  StrToFloat(Edit3.Text)> StrToFloat(Edit2.Text)  then
showmessage('还款金额不能大于欠费金额!')
else
begin
vPayment := StrToFloat(Edit3.Text);
ADOQuery1.Close;
bComplete:=false;
try
repeat
  ADOQuery1.SQL.Clear;
  ADOQuery1.SQL.Add('select top 1 票据号,实收金额,(-1*应找金额) as 欠费金额 from tb_sf where 应找金额<0');
  ADOQUery1.SQL.Add(' and 病人id=:brid');
  ADOQUery1.SQL.Add(' order by 票据号');
ADOQuery1.Parameters.ParamByName('brid').Value:=strtoint(label4.Caption);
  ADOQuery1.Open;
  if not ADOQuery1.Eof  then
  begin
    vItemPay := ADOQuery1.FieldByName('欠费金额').AsFloat;
    vItemPaid := ADOQuery1.FieldByName('实收金额').AsFloat;
    sItemNo := ADOQuery1.FieldByName('票据号').AsString;
    ADOQuery1.Close;
    ADOQuery1.SQL.Clear;
    if (vItemPay>vPayment) then
      begin
      vPay := strtofloat(format('%.2f',[vPayment-vItemPay]));
      vItemPaid := vItemPaid vPayment;
    end
    else
    begin
      vItemPaid := vItemPaid vItemPay;
      vPay := 0;
    end;        ADOQuery1.SQL.Add('update tb_sf set 实收金额=:vItemPaid,应找金额=:vPay where 票据号=:sItemNo');
      ADOQUery1.SQL.Add(' and 应收金额>0');
    ADOQuery1.Parameters.ParamByName('vPay').Value:= vPay;
    ADOQuery1.Parameters.ParamByName('vItemPaid').Value:= vItemPaid;
    ADOQuery1.Parameters.ParamByName('sItemNo').Value:= sItemNo;
    ADOQuery1.ExecSQL;
    if (vItemPay>vPayment) then
      vPayment := 0
    else
      vPayment := vPayment-vItemPay;
  end
  else
  begin
    bComplete := True;
  end;
until (bComplete or (vPayment<=0));
showmessage('还款成功');
edit1.Text:='';
edit2.Text:='';
edit3.Text:='';
label4.Caption:='';
edit1.SetFocus;
except
showmessage('还款未成功');
end;
end;
end;    
------
我的编程起步于ktop,我将永远支持ktop
malanlk
尊榮會員


發表:20
回覆:694
積分:577
註冊:2004-04-19

發送簡訊給我
#22 引用回覆 回覆 發表時間:2005-10-18 07:59:52 IP:203.69.xxx.xxx 未訂閱
else
  begin
    ADOQuery1.Close;
    bComplete := True;
  end;
大致這樣吧...
系統時間:2024-05-12 17:09:41
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!