I言語自習書_05:請求書発行システムの開発

●それでは実際に請求書発行システムを0から作ってみましょう。

    1.最初に必要なテーブルを設計します。
    1.1請求書を見ながら必要な項目名を抜き出します。。
    ①会社コード,②会社名,③請求額,④請求日,⑤請求書番号,⑥頁,⑦頁数,⑧小計額,⑨消費税額,
    ,⑩伝票番号(複数個),⑪年月日(複数個),⑫商品コード(複数個),⑬商品名(複数個),⑭数量(複数個),⑮単価(複数個),⑯金額(複数個), 位でしょうか、再度テーブル化のポイントを確認します。
    (実際に請求書は、多分これだけでは無いと思いますが、自習ですので必要最小限の物のみとしています)
    1.1.1 複数個のデータは行に分割して持つ。

    1.1.2 主キーの同じ物を別テーブルに分割して持つ。

    1.1.3 他の行から導き出せる物は元テーブルに持たないが、処理後のテーブルには持つ。

    1.2.1 最初に1.1.1の対応をします、⑩伝票番号(複数個)、⑪年月日(複数個),⑫商品コード(複数個)、⑬商品名(複数個)、⑭数量(複数個)、⑮単価(複数個)、⑯金額(複数個)が複数個有りますが、 この中で主キーは伝票番号がユニークで有るとすると⑩伝票番号と成ります、又、複数個を同じとするには①会社コード単位に請求書を作るのでこの2個を主キーとします。
    1.2.2 上記の中で1.1.2を実行し⑫商品コードのみが主キーと成る、⑬商品名(複数個)と⑮単価(複数個)は、別テーブルに分割します。
    ◎ただし、単価が商品コードのみで決まる事が前提です。
    1.2.3 残りの複数でない物を対応します。①会社コード,②会社名,③請求額,④請求日,⑤請求書番号,⑥頁,⑦頁数,⑧小計額,⑨消費税額です。 尚、⑥頁は実際に作ってみた結果ではテーブル上には不要でしたので省きます。 この中で主キーと成る物に①会社コードが有り、②会社名と2つを別テーブルに分割します。
    整理して書くと下記と成ります。
    (1){①会社コード,⑩伝票番号}{⑪年月日,⑫商品コード,⑬商品名,⑭数量,⑮単価,⑯金額)

    (2){⑫商品コード}(⑬商品名,⑮単価)

    (3){①会社コード}(②会社名,③請求額,④請求日,⑤請求書番号,⑦頁数,⑧小計額,⑨消費税額)

    (4){①会社コード}(②会社名)

    1.2.4 請求書の元と成るテーブルは納品システム等別のシステムで作りますが、今回は納品システムは作らないので単に納品書を作成するテーブルとプログラムを作ります。
    請求書を作るには(1)と(3)のテーブルの内の分割した項目以外があれば良いので、①会社コード,③請求額,④請求日,⑤請求書番号,⑧小計額,⑨消費税額,⑩伝票番号,⑪年月日,⑫商品コード,⑭数量,⑯金額の11個が必要ですが、 この内で他から導き出せる物は不要なので,③請求額,⑧小計額,⑨消費税額,⑯金額の4個を除き、請求書発行システムで新たに付加される物が④請求日,⑤請求書番号の2個ですので、 残りの5個が必要と成ります。尚、請求書を2重発行しない為に請求日も持つ事とします。
    (5){⑩伝票番号}(⑪年月日,①会社コード,⑫商品コード,⑭数量,④請求日)

    □注意:これは主キーが伝票番号のみですが、伝票番号だけでは将来同じ番号が発生してしまうので、実際のシステムを作る場合は、年等を主キーに加えるか、このままの場合、 は、重複する前に、必ず過去のデータが消されている必要が有ります。
    1.2.5 伝票番号と請求書番号は伝票毎にユニークな値を付与する必要が有り、使用済み番号を記憶しておく必要が有るので番号を記憶するテーブルも作ります。
    (6){伝票番号コード}(伝票番号)

    1.3それでは実際にテーブルを設計します。

    I言語ではデーブルの設計と言っても全く自由に設計出来る訳では無く、管理と運用を簡単にする為命名規約が有るのでそれを確認します。
    1.3.1 列名はシステム内でユニークで有る必要が有ります、今回は自習用ですので先頭に自習_を付けてユニークにします。
    1.3.2.1 マスター系テーブル名は先頭を英字4桁の許可と同じにする必要が有ります、今回はインストールで設定されている許可のZZZYを使用する事にします。
    ◎I言語では常に存在しているテーブルをマスターデータベースに持ち、一時的に作られるテーブルをワークデータベースに持つように成っています。
    1.3.2.2 マスター系テーブル名は先頭の許可の次を英字2桁の許可区分と同じにする事を推奨しています、今回はインストールで設定されている許可区分のAAを使用する事にします。
    1.3.2.3 マスター系テーブル名の最後は実表(または_TABLE)とする必要があります。
    それでは設計します。
    1.4 最初にデータ辞書を作ります。
    ①会社コード---自習_会社コード---CHAR(13)------------[型1='9',長さ2=13]
    (ポイント)型1='9'数字のみ入力可能です。
    (ポイント)長さ2=13は最低文字数で必ず13桁必要の意味と成ります。
    ②会社名-------自習_会社名-------NCHAR(30)-----------[型1='/',長さ2=1]
    (ポイント)型1='/'は日本語が入力出来ます。
    ③請求額-------------自習_請求額-------DECIMAL(15,0)-[型1='+']
    (ポイント)型1='+'は正の数値の入力が出来ます。
    ④請求日-----自習_請求日---------------CHAR(8)-------[型1='D']
    (ポイント)型1='D'は年月日を入力出来ます。
    (ポイント)年月日のデータ型はRDBMS毎に動きが異なるので、I言語ではCHAR(8)を使います。
    ⑤請求書番号---------自習_請求書番号---DECIMAL(9,0)--[型1='+',型2='C']、
    (ポイント)型2='C'は数値情報では無いので、表示で3桁毎のカンマを付加しない指定です。
    ⑦頁数---------------自習_頁数---------DECIMAL(3,0)--[型1='+']
    ⑧小計額-------------自習_小計額-------DECIMAL(15,0)-[型1='+']
    ⑨消費税額-----------自習_消費税額-----DECIMAL(15,0)-[型1='+']
    ⑩伝票番号(複数個)---自習_伝票番号-----DECIMAL(9,0)--[型1='+',型2='C']
    ⑪年月日-------------自習_年月日-------CHAR(8)-------[型1='D',長さ2=1]
    (ポイント)長さ2=1は最低文字数で必ず1文字必要ですので、空白の日付は入力出来ません。
    ⑫商品コード---------自習_商品コード---CHAR(11)------[型1=' ',長さ2=11]
    ⑬商品名-------------自習_商品名-------NCHAR(30)-----[型1='/',長さ2=1]
    ⑭数量---------------自習_数量---------DECIMAL(4,0)--[型1='+']
    ⑮単価---------------自習_単価---------DECIMAL(7,0)--[型1='+']
    ⑯金額---------------自習_金額---------DECIMAL(12,0)-[型1='+']
    伝票コード-----------自習_伝票コード---NCHAR(8)------[型1='/',長さ2=1,チェック=CHECK,チェック61=納品書,請求書]
    (ポイント)「チェック=CHECK,チェック61=納品書,請求書」で納品書と請求書の2つの伝票番号を持つ事とします。
    ここでデータ辞書を作って下さい。ペイジ」
    〇許可ZZZYのデータ辞書を作るので、許可ZZYの管理者であるZZZZZZZYの使用者で作ります。。
    〇自習書_03でデータ辞書の作り方は自習済みですので、結果のみを表示します。

    1.5 テーブルを作ります。
    (1){①会社コード,⑩伝票番号}(⑪年月日,⑫商品コード,⑬商品名,⑭数量,⑮単価,⑯金額)
    テーブル名:?_WW?_ 請求書明細実表 (作業用テーブルは先頭に?_WW?を付加します)
    主キーの数=2
    1:自習_会社コード
    2:自習_伝票番号 
    3:自習_年月日 
    4:自習_商品コード 
    5:自習_商品名 
    6:自習_数量  
    7:自習_単価  
    8:自習_金額
    (2){⑫商品コード}(⑬商品名,⑮単価)
    テーブル名:ZZZYAA_商品実表 (マスター系テーブルは先頭にZZZYAA_を付加します)
    主キーの数=1
    1:自習_商品コード 
    2:自習_商品名 
    3:自習_単価 
    (3){①会社コード}(②会社名,③請求額,④請求日,⑤請求書番号,⑦頁数,⑧小計額,⑨消費税額)
    テーブル名:?_WW?_請求書代表実表 
    主キーの数=1
    1:自習_会社コード
    2:自習_会社名
    3:自習_請求額 
    4:自習_請求日
    5:自習_請求書番号
    6:自習_頁数
    7:自習_小計額 
    8:自習_消費税額
    (4){①会社コード}(②会社名)
    テーブル名:ZZZYAA_会社実表
    主キーの数=1
    1:自習_会社コード 
    2:自習_会社名 
    (5){⑩伝票番号}(⑪年月日,①会社コード,⑫商品コード,⑭数量,④請求日)
    テーブル名:ZZZYAA_納品実表
    主キーの数=1
    1:自習_伝票番号
    2:自習_年月日
    3:自習_会社コード
    4:自習_商品コード
    5:自習_数量
    6:自習_請求日
    (6){伝票番号コード}(伝票番号)
    テーブル名:ZZZYAA_伝票番号実表
    主キーの数=1
    1:自習_伝票コード
    2:自習_伝票番号
    〇ここでマスター系のZZZYAA_商品実表とZZZYAA_会社実表とZZZYAA_納品実表とZZZYAA_伝票番号実表の4個のテーブルを作ります。
    〇自習書_03でテーブルの作り方は自習済みですので、結果のみを表示します。





    2.テーブルを元に更新のプログラムを作ります。
    2.1 ZZZZ303033に「自習 商品更新」を作ってデータを登録します。
    〇自習書_03でプログラムの作り方は自習済みですので、結果のみを表示します。


    2.2 ZZZZ303034に「自習 会社更新」を作ってデータを登録します。


    2.3 納品更新では伝票番号はユニークな番号を使う必要が有るので先に、ZZZZ303035に「自習 伝票番号更新」を作ります。


    ここでプログラムを追加して入力出来る範囲を指定しています。
    〇START(1,2,3の操作を入れた直後に実行)の処理でW0CHECKに条件で1と2を入れCHECK=(最小値,最大値)で範囲を指定しています。
    〇修正時にキーで有る伝票コード内の処理は迂回されてしまうのでSTARTに書く必要が有ります。
    〇作成時は伝票コードが変わるので再度W0CHECKをCOPY=CHECKで実行しています。
    〇8桁に成っているのは最後にチェックディジットを追加して9桁にする為です。

    〇最大値を入れて有るのは、値がオーバーした場合先頭番号に戻す為で永久に桁数を増やすわけには行かないのでいつかは戻る事になります。
    2.3 ZZZZ303036に「自習 納品更新」を作ってデータを登録します。
    納品更新では商品コードは商品実表に有る物で会社コードは会社実表に有る物と成ります、この指定はデータ辞書で対応出来るのでデータ辞書を修正します。


    データ辞書を修正したので、プログラムを作ります。


    210 CONTROL=SCROLL
    〇複数行表示を1行表示に変更しています。
    1410 START
    〇操作時の処理を実行します。
    1420 =IF{_START!=2}EXIT{};
    〇2の作成以外は終了します。
    1430 =SQL{BEGIN TRANSACTION};
    〇トランザクションを開始します。
    1440 =PROGRAM{0,?_MM?_伝票番号実表,W0.自習_伝票番号=}
    1442 = {WN.自習_伝票コード='納品書'}{};
    〇伝票番号を読み込みます。
    1450 =IF{_PROGRAM_COUNT!=1}ERROR{伝票番号実表,納品書 エラー};
    〇該当データーが無い時はエラーとします。
    1460 =IF{W0.自習_伝票番号 >19999000}
    1462 = SET{W0.自習_伝票番号=10000000};
    〇オーバーフローの可能性が有る時は初期値に戻します。
    1470 =COMPUTE{W0.自習_伝票番号+=1};
    〇今回用に番号を1加算します。
    1480 =PROGRAM{3,?_MM?_伝票番号実表,W0.自習_伝票番号}
    1482 = {WN.自習_伝票コード='納品書'}{};
    〇加算した結果をテーブルに書き込みます。
    1490 =SQL{COMMIT TRANSACTION};
    〇コミットで更新を完了します。
    1492 =SET{_DIGIT11=W0.自習_伝票番号};
    〇デジットコードを設定します。
    1494 =COMPUTE{W0.自習_伝票番号*=10};
    〇デジットコードを1桁目にする為元の番号を10倍します。
    1496 =COMPUTE{自習_伝票番号=W0.自習_伝票番号+_DIGIT11};
    〇デジットコードを1桁目に加算します。
    1500 DATA={KO}?&.DATA&自習_伝票番号?
    〇伝票番号は入力しないので出力項目に変更します。

    〇100000016は削除済で今回の処理対象には成りません。
    〇100000024請求日が入っているので請求済みで処理対象には成りません。
    〇100000032は2024年3月の月次処理で2月までの日付のデータを処理するので処理対象には成りません。
    〇請求書は自習用ですので1ページ2行まで印字可能としたので、長野商事が1件で1枚、飯田株式会社が2件で1枚、原沢商店で3件の2枚の計4枚出来れば正解と成ります。
    3.それでは印刷のレイアウトZZZZ010236の(テスト印刷表示レイアウト 更新)で作ります。
    〇少し量は多いですが内容は簡単なのでZZZZ010237の(印刷表示レイアウト 文法表示)で理解しながら作ってみて下さい。


    100 VERSION,13
    200 LINE_SET,L2,0.2
    300 CHAR_SET,C8,8,,,C3,3,,,C4,4,,,C5,5
    400 *(1)会社コード,会社名,請求額,請求日,請求書番号,頁,頁数
    500 *小計額,消費税(9)
    600 DATA,C3,,22,50,13
    700 DATA,C4,,22,57,30
    800 DATA,C5,,45,80,23,E ,C3,,163,144,19,+
    900 DATA,C3,,150,40,10,D
    1000 DATA,C3,,150,45,9
    1100 DATA,C3,,150,50,3,+
    1200 DATA,C3,,157,50,3,+
    1300 DATA,C3,,163,132,19,+
    1400 DATA,C3,,163,138,19,+
    1500 OCCURS,1,0,6
    1600 *(10,16)伝票番号,年月日,商品コード,商品名,数量,単価,金額(23)
    1700 DATA,C3,,20,120,9
    1800 DATA,C3,,40,120,10,D
    1900 DATA,C3,,60,120,11
    2000 DATA,C3,,80,120,30
    2100 DATA,C3,,132,120,5,+
    2200 DATA,C3,,144,120,9,+
    2300 DATA,C3,,163,120,19,+
    2400 OCCURS,4,0,6
    2500 X_LINE,L2,18,117,195
    2600 OCCURS
    2700 X_LINE,L2,20,62,110 ,87
    2800 BOX,L2,18,110,195,148
    2900 Y_LINE,L2,38,110,129 ,58,130
    3000 Y_LINE,L2,142,110,148 ,160
    3100 TEXT,請求書,C8,,85,35
    3200 TEXT,xx電気,C4,,140,70
    3300 TEXT,御中,C4,,85,57
    3400 TEXT,年月日,C3,,140,40
    3500 TEXT,請求書番号,C3,,134,45
    3600 TEXT,PAGE,C3,,143,50

    3700 TEXT,/,C3,,155,50
    3800 TEXT,ご請求額,C5,,22,80
    3900 TEXT,伝票番号,C3,,22,112
    4000 TEXT,年月日,C3,,40,112
    4100 TEXT,商品,C3,,70,112
    4200 TEXT,数量,C3,,131,112
    4300 TEXT,単価,C3,,147,112
    4400 TEXT,金額,C3,,173,112
    4500 TEXT,小計額,C3,,145,132
    4600 TEXT,消費税,C3,,145,138
    4700 TEXT,合計,C3,,145,144
    4800 TEXT,?_PAGE?,C3,,180,156

    4.月次の自習_請求書月次処理を作ります。
    〇月次処理は月初の稼働1日目に時間起動処理として作ります。
    〇時間起動処理は、ZZZZ010222の(テスト 時間起動 プログラム更新)で作ります。

    〇時が09で分が00ですので9時に時間実行されます。
    〇タイミングがMで始末が+で何日が01で月次稼働の1日目に実行します。
    〇M1は50以上が時間起動用です。

    一応3個のジョブで構成しました。

    □操作上でTとすればテスト実行します。
    □3つのジョブを一度に実行したい時はZZZZ010232の(テスト 時間起動 実行)で先頭行を選んでALLで実行します。
    100 =SET{WC.TODAY=_TODAY}; 今日の日付をWC.TODAYにセット*
    〇請求日を決める為今日の年月日をWC.TODAYに入れます。(年4文字月2文字日2文字の8文字で構成されています。
    200 =DROP_TABLE{?_WW?_請求書代表実表};
    〇請求書代表実表のテーブルを消します。(テーブルが無い場合は何もしません)。
    〇作業テーブルはDROP_TABLEで消す事が出来ます。(マスターテーブルはDROP_TABLEでは消せません)。
    300 =DROP_TABLE{?_WW?_請求書明細実表};
    〇請求書明細実表のテーブルを消します。(テーブルが無い場合は何もしません)。
    400 =CREATE_TABLE2{?_WW?_請求書代表実表,自習_会社コード,*}
    500 ={自習_会社名,*,自習_請求額,*,自習_請求日,*,自習_請求書番号,*
    510 =,自習_頁数,*,自習_小計額,*,自習_消費税額,*};
    〇請求書代表実表のテーブルを作っています。
    〇CREATE_TABLE2はI言語が使う列を作成しません。(作業テーブルは不要なので)
    〇列名はデータ辞書に有る場合はデータ型を*とする事でデータ辞書から設定されます。
    700 =CREATE_TABLE2{?_WW?_請求書明細実表,自習_会社コード,*,
    800 = 自習_伝票番号,*}{自習_年月日,*,自習_商品コード,*,
    900 = 自習_商品名,*,自習_数量,*,自習_単価,*,自習_金額,*};
    〇請求書明細実表のテーブルを作っています。
    1000 *****( 請求書明細 作成 )********
    1100 =SQL{BEGIN TRANSACTION};
    〇納品実表を更新するのでトランザクションを開始します。
    1200 =SQL{INSERT INTO ?_WW?_請求書明細実表(自習_会社コード,
    1300 = 自習_伝票番号,自習_年月日,自習_商品コード,自習_数量
    1400 = )SELECT 自習_会社コード,自習_伝票番号,自習_年月日,
    1500 = 自習_商品コード,自習_数量
    1600 = FROM ?_MM?_納品実表 ?_LOCK1? WHERE Z_CANCEL=' '
    1700 = AND 自習_年月日<'?WC.TODAY[1;6]?01'
    1800 = AND 自習_請求日=' ' AND Z_CANCEL=' ' ?_LOCK2?};
    〇納品実表から請求書明細実表を作っています。
    〇Z_CANCEL=' 'で削除済みデータは除いています。(2か所有るのは単なるプログラミングミスです)
    〇自習_年月日<'?WC.TODAY[1;6]?01'で処理月の初日以降はのぞきます。
    〇自習_請求日=' ' で請求書発行分は除きます。
    〇_LOCK1と_LOCK2で占有ロックをかけて他から更新されないようにしています。
    1900 =SET{W0.明細_CNT=_SQL_COUNT_123};
    〇INSERTによる登録件数をW0.明細_CNTに設定したます。
    2000 *****( 納品実表, 請求日 修正 )******
    2100 =SQL{UPDATE ?_MM?_納品実表 SET 自習_請求日='?WC.TODAY?'
    2200 = WHERE 自習_伝票番号 IN(SELECT 自習_伝票番号 FROM
    2300 = ?_WW?_請求書明細実表)};
    〇請求書明細実表に作られたデータは納品実表に請求日を入れています。
    2400 =IF{_SQL_COUNT_123<>W0.明細_CNT}
    2500 = ERROR{UPDATE 納品実表 更新件数 エラー 1};
    〇請求書明細実表に作られたデータの件数と納品実表に請求日を入た件数が合わない場合は念の為エラーとしています。
    2600 =SQL{COMMIT TRANSACTION};
    〇納品実表を修正したのでコミットでトランザクションを終了しています。
    2700 *****( 請求書代表 作成 )********
    2800 =SQL{INSERT INTO ?_WW?_請求書代表実表
    2900 = (自習_会社コード,自習_請求日) SELECT DISTINCT
    3000 = 自習_会社コード,'?WC.TODAY?' FROM ?_WW?_請求書明細実表};
    〇請求書代表実表に会社コードと請求日を作成します。
    〇DISTINCTで同じ会社コードは1件と成ります。
    〇請求日は'?WC.TODAY?'で今日の年月日を入れています。

    100 *****( 請求書番号 処理 )********
    200 =SQL{BEGIN TRANSACTION};
    〇伝票番号実表を更新するのでトランザクションを開始します。
    210 =SQL_SET{W0.MAX}{SELECT COUNT(*) FROM ?_WW?_請求書代表実表};
    〇請求書代表実表の件数分の番号が必要なのでW0.MAXに設定したいます。
    300 =PROGRAM{0,?_MM?_伝票番号実表,W0.自習_伝票番号=}
    400 = {WC.自習_伝票コード='請求書'}{};
    〇伝票番号実表から請求その伝票番号をW0.自習_伝票番号に受け取ります。
    500 =IF{_PROGRAM_COUNT!=1}ERROR{伝票番号実表にデータが有ません};
    〇該当データが無い場合エラーとしています。(PROGRM{0...はデータが無くても正常終了します。)
    600 =COMPUTE{W0.END=W0.自習_伝票番号+W0.MAX};
    〇W0.ENDに今回の伝票番号の最後の値を計算しています。
    700 =IF{W0.END>29999999}SET{W0.自習_伝票番号=20000000}
    〇W0.ENDが29999999より大きい場合はオーバーしているので初期値の20000000に戻しています。
    800 = COMPUTE{W0.END=W0.自習_伝票番号+W0.MAX};
    〇W0.ENDを再度計算しています。
    900 =SET{W0.NUMBER=W0.自習_伝票番号};
    〇W0.NUMBERに伝票番号の初期値を設定しています。
    1000 =PROGRAM{3,?_MM?_伝票番号実表,W0.自習_伝票番号=W0.END}
    1100 = {WC.自習_伝票コード}{};
    〇伝票番号実表の伝票番号をW0.ENDでUPDATEしています。
    1200 =SQL{COMMIT TRANSACTION};
    〇伝票番号実表の更新が終ったのでコミットしてトランザクションを終了します。
    1300 *****( 請求書番号 付加 )********
    1400 =SQL1{SELECT 自習_会社コード FROM ?_WW?_請求書代表実表
    1500 = ORDER BY 自習_会社コード};
    〇請求書代表実表を一行づつ読み込むSQL文を設定しています。
    1600 =SQL1_NEXT:SQL1_NEXT{WC.自習_会社コード}JUMP{SQL1_END};
    〇1件データを読んでいます。
    〇データが終るとSQL1_ENDに飛びます。
    1700 =COMPUTE{W0.NUMBER+=1};SET{_DIGIT11=W0.NUMBER};
    〇W0.NUMBERに1を加えで、チェックディジットを_DIGIT11に設定します。
    1800 =COMPUTE{W0.自習_請求書番号=W0.NUMBER*10};
    〇チェックディジットを1桁目としたいのでW0.NUMBERを10倍した物をW0.自習_請求書番号に設定しています。
    1900 =COMPUTE{W0.自習_請求書番号+=_DIGIT11};
    〇チェックディジットを1桁目に足しています。
    2000 =SQL{UPDATE ?_WW?_請求書代表実表
    2100 = SET ?_VRE&W0.自習_請求書番号?
    2200 = WHERE ?_VRE&WC.自習_会社コード?};
    〇請求書代表実表のジットを請求書代表実表を設定しています。
    2300 =IF{_SQL_COUNT_123<>1}
    2400 = ERROR{UPDATE 請求書代表 請求書番号 エラー};
    〇1行更新でない場合念のためエラーとしています。
    2500 =BACK{SQL1_NEXT};
    〇次のデータに行きます。
    2600 =SQL1_END:

    100 ******( 請求書明細 計算処理 )*******************
    110 =SQL_SET{W0.明細}{SELECT COUNT(*) FROM ?_WW?_請求書明細実表};
    〇請求書明細実表の件数をW0.明細に設定します。
    200 =UPDATE{?_WW?_請求書明細実表,自習_商品名,自習_単価,自習_金額}
    300 = {I.自習_商品名,I.自習_単価,I.自習_単価*自習_数量}
    400 = {?_MM?_商品実表 I WHERE Z_CANCEL=' '
    500 = AND O.?_NE&I.自習_商品コード?};
    〇請求書明細実表を商品実表から商品名と単価と金額を更新します。
    600 =IF{_SQL_COUNT_123<>W0.明細}
    700 = ERROR{UPDATE 請求書明細 計算処理 エラー};
    〇更新件数が合わない場合念のためエラーとします。
    800 ******( 請求書代表 計算処理 )*******************
    810 =SQL_SET{W0.代表}{SELECT COUNT(*) FROM ?_WW?_請求書代表実表};
    〇請求書代表実表の件数をW0.代表に設定します。
    900 =UPDATE{?_WW?_請求書代表実表,自習_小計額,自習_消費税額,
    1000 = 自習_請求額,自習_頁数,自習_会社名}{
    1100 = 小計,小計*0.1,小計+小計*0.1,頁数,I2.自習_会社名}
    1200 = {(SELECT 自習_会社コード,SUM(自習_金額) AS 小計,
    1300 = ?_ROUNDUP(COUNT(*)/2.0;0)? AS 頁数
    1400 = FROM ?_WW?_請求書明細実表 GROUP BY 自習_会社コード) I1
    1500 = ,?_MM?_会社実表 I2 WHERE I1.?_NE&O.自習_会社コード?
    1600 = AND I2.?_NE&O.自習_会社コード?};
    〇請求書代表細実表を会社実表と請求書明細実表を使って小計額,消費税額,請求額,頁数,会社名を更新しています。
    〇_RUNDUOPは切り上げのSQLに置き換えられます、RDBMS毎に切り上げの方法が異なるのでI言語でシステム変数を用意しています。
    1700 =IF{_SQL_COUNT_123<>W0.代表}
    1800 = ERROR{UPDATE 請求書代表 計算処理 エラー};
    〇更新件数が合わない場合念のためエラーとします。
    △請求書システムを作る場合は主キーが請求代表実表は会社コードのみで、請求明細実表は伝票番号がオーバーフローすれば、同じ主キーとなる可能性は有るので、今回のように月一回つまり一日一回の処理で有れば、主キーに請求日を追加でも可能ですが、一日に2回以上発行する可能性が有る場合は年月+請求書番号及び年月+伝票番号等を主キーにする必要が有ります。
    △今回は月次1回を想定したシステムで、印刷も一か月間は同じ内容で印刷出来きますが、不定期で一日に何度も発行するような場合は、月次処理としてではなく、メニューから起動し、作業テーブルでは無く請求システムのようにマスタテーブルで何時でも再発行出来るようなテーブル構造とする必要が有ります。 >
    5.最後に実際に印刷するジョブを作ります。


    100 PROGRAM=NOT
    200 TABLE=&X1,?_W_INP?_請求書明細実表
    〇TABLE=でテーブル変数を設定します。(これにより沢山のテーブル変数が用意されるので、プログラムを簡単にする事が出来ます)
    □テーブルが存在しないと異常終了してしまうので、このプログラムは完璧では無いですが、対応は少しややこしいのでこのままとします、尚、SET_TABLEで設定する事も可能ですがTABLE=はプログラムの読み出し時に実行されるので、REPEAT=等の呼び出し時に実行される命令にも変数が使えますが SET_TABLEは実行時に設定されるのでREPEAT=等では使えないのでこのようにします。 対応方法は一つ前のプログラムでテーブルが有るか確認し無ければエラーで止まり、ある場合この処理を実行し、この処理の終わりでEXIT(0)でメニューに戻るように作ります。
    ☆システム変数の_WWはメニューの処理種類がINPUTの時とOUTPUTの時で異なります、時間起動では必ずINPUTで実行されますが請求素発行ではマスターテーブルの更新が無いのでOUTPUTにしています、 なので_WWは使えません、INPUTでの_WWと同じにするため_W_INPを使います。
    300 TABLE=&X2,?_W_INP?_請求書代表実表
    400 BEGIN
    〇BEGINは開始直後に実行する処理用です。
    500 =SQL_SET{枚数,自習_請求日}{SELECT
    600 = SUM(自習_頁数),MAX(自習_請求日) FROM ?&X2.TABLE?};
    〇請求書代表実表から頁数を合計して総枚数と請求日を設定しています。(請求日は全て同じですが1行にする為MAXを付けています)
    700 DATA={O}?&X2.DATA&自習_請求日?
    〇請求日を表示する場所です。
    800 DATA={O}枚数{5,,+}
    〇総枚数を表示する場所です。
    900 DATA=開始頁?&X2.DATA2&自習_頁数?
    〇印刷を開始するページを入れます、先頭からの場合は何も入れません。
    1000 CHECK=(0,?枚数?)
    〇印刷を開始するページは0から総枚数までと成ります。
    1100 =IF{_DATA=0}SET{修了頁=}EXIT2{修了頁};
    〇印刷を開始するページを指定しない時は終了頁の入力を迂回します
    1200 DATA=修了頁?&X2.DATA2&自習_頁数?
    〇印刷を終了するページを入れます。
    1300 CHECK=(?開始頁?,?枚数?)
    〇印刷を終了するページは開始頁から総枚数までです。
    1400 =SET{W0.END=0};
    〇処理終了を判定するW0.ENDに0を入れます。
    1500 =SQL1{SELECT ?&X1.ALL? FROM ?&X1.TABLE? ORDER BY
    1600 = 自習_会社コード,自習_伝票番号};
    〇請求書明細実表を抜き出すSQL文です。
    1700 =SQL1_NEXT{?&X1.WORK?}ERROR{データ無し};
    〇請求書明細実表の全ての列を1件分、次のデータと比較する為、作業データに先読みします。
    1800 =IF_ERROR_WRITE_OPEN{1,?_WORK?_DATA.TXT,OT}ERROR{};
    〇印刷データを書き込むファイルをオープンします。
    2000 =FIRST_PAGE: SET{W0.頁=1};
    〇会社コードが変わった最初の処理で実行されるので、W0.頁を1に設定します。
    2100 =SET{WC.自習_会社コード_O=WC.自習_会社コード};
    〇会社コードをWC.自習_会社コード_Oにキープしてます。
    2200 =SQL_SET{?&X2.WORK?}{SELECT ?&X2.ALL? FROM ?&X2.TABLE?
    2300 = WHERE 自習_会社コード='?WC.自習_会社コード_O?'};
    〇会社コードの請求書代表実表のデータを抜き出しています。
    2400 REPEAT=&X2.ALL_COUNT
    2500 =SET{WN.?&X2.ALL_##?=?&X2.WORK_##?};
    2600 REPEAT=
    〇請求書代表実表のデータをすべてWN.から始まるデータ名に設定しています。
    ☆?&X2.WORK?は数値情報がW0.で始まり空の状態でファイルに書くと0を書いてしまうので、空白を書くようにWN.付に設定し直します。
    2700 =IF{_SQL_SET_COUNT<>1}
    2800 = WRITE_CLOSE{1}ERROR{?WC.自習_会社コード_O? (会社)無し};
    〇請求書代表実表に該当会社コードが無い場合続行不能ですのでエラーとしています。
    2900 =NEXT_PAGE: SET{W0.LINE=1};
    〇請求書印刷の先頭処理ですので1行目に該当データを印刷する為W0.LINEを1に設定しています。
    3000 REPEAT0=2,1
    3100 REPEAT=&X1.ALL_COUNT
    3200 =SET{WN.?&X1.ALL_##?_$$=};
    3300 REPEAT0=
    〇印刷データを行数不足でも空白を印刷する為全てに空白を転送します。

    3400 =NEXT_LINE:
    3500 REPEAT=&X1.ALL_COUNT
    3600 =SET{WN.?&X1.ALL_##?_?W0.LINE?=?&X1.WORK_##?};
    3700 REPEAT=
    〇該当行の位置に全データを設定しています。
    〇最後に_?W0.LINE?が付いているので該当行の位置にデータを設定します。
    3800 =SQL1_NEXT:SQL1_NEXT{?&X1.WORK?}SET{W0.END=1}JUMP{WRITE};
    〇次のデータを読んでいます。
    〇データーが無く成った時はW0.ENDに1を入れてWRITEに飛びます。
    3900 =COMPUTE{W0.LINE+=1};
    〇印刷行を下げる為W0.LINEに1を加えます。
    4000 =IF{WC.自習_会社コード=WC.自習_会社コード_O}
    4100 = IF{W0.LINE<3}BACK{NEXT_LINE};
    〇会社コードが同じで印刷行数に達していない場合は同じ紙に印刷するのでNEXT_LINEに戻ります。
    4200 =WRITE:
    4300 =IF{WN.自習_頁数=W0.頁}JUMP{SET};
    4400 =SET{WN.自習_請求額_X =};
    4500 =SET{WN.自習_小計額_X =};
    4600 =SET{WN.自習_消費税額_X=};
    4700 =JUMP{WRITE1};
    4800 =SET:
    4900 =SET{WN.自習_請求額_X =WN.自習_請求額};
    5000 =SET{WN.自習_小計額_X =WN.自習_小計額};
    5100 =SET{WN.自習_消費税額_X=WN.自習_消費税額};
    5200 =WRITE1:
    〇請求額と小計と消費税額は最後の頁のみ印刷します。
    5300 =WRITE{1
    5400 REPEAT=&X2.ALL_COUNT
    5500 6+ =,W0.頁
    〇頁はテーブル上には無いので6番目の頁数の前に追加します。
    5600 3- 7- 8-=,WN.?&X2.ALL_##?
    〇3以外且つ7以外且つ8以外の時に実行します。
    5700 3+|7+|8+=,WN.?&X2.ALL_##?_X
    〇3又は7又は8の請求額と小計と消費税額は_X付きのデータ名を使います。
    5800 REPEAT0=2
    5900 REPEAT=&X1.ALL_COUNT,2
    6000 = ,WN.?&X1.ALL_##?_$$
    6100 REPEAT0=
    〇請求明細の全行分を設定しますが、請求明細の先頭の会社コードは不要なのでREPEAT=&X1.ALL_COUNT,2と2番目から始まるようにしています。
    6200 = };
    6300 =IF{W0.END=1}JUMP{END};
    〇W0.ENDが1の時はもうデータが無いのでENDに飛びます。
    6400 =COMPUTE{W0.頁+=1};
    〇1頁分を書いたのでW0.頁に1を加えます。
    6500 =IF{WC.自習_会社コード=WC.自習_会社コード_O}BACK{NEXT_PAGE};
    〇会社コードが同じ場合次のページを処理するのでNEXT_PAGEに戻ります。

    6600 =BACK{FIRST_PAGE};
    〇会社コードが異なる場合はFIRST_PAGEに戻り1ページからと成ります。
    6700 =END:
    6800 =WRITE_CLOSE{1};
    〇ファイルをクローズします。
    6900 =SQL_FILE2{?_WORK?_LAYOUT.TXT,OT}{SELECT SYSTEM_PRINT_DATA
    7000 = FROM ?_MP_ZZZZ?ZZ_PRINT_TABLE WHERE
    7100 = SYSTEM_PRINT='ZZZYAA_SEIKYUUSYO' ORDER BY SYSTEM_SEQ};
    〇印刷フォーマットデータをファイルに書きます。
    7200 =IF{開始頁=0}SET{WC.START=,WC.STOP=}JUMP{EXE};
    7300 =SET{WC.START=開始頁};
    7400 =IF{修了頁=0}SET{WC.STOP=}JUMP{EXE};
    7500 =SET{WC.STOP=修了頁};
    ☆7200から7500までは印刷プログラムで開始位置が0はエラーとしていた為の処置ですが、0は1と見なすようにVER14で修正するので直接開始頁と終了頁を指定しても問題無く動くように成ります。
    7600 =EXE:EXE{?_IPRINT?,?_REAL_TEST? ?_WORK?_DATA.TXT
    7700 = ?_WORK?_LAYOUT.TXT ?WC.START? ?WC.STOP?};
    〇印刷プログラムを起動します。
    〇テスト実行は?_REAL_TEST?がTESTに成っており、紙では無く画面に表示されます。([Enter]で次のページが表示出来ます)
    7800 DATA=END{1}
    〇印刷後ここの入力で止まります。
    7900 =EXIT{_END};
    〇Enterでプログラムが終了します。。




    〇最後のページで無い物は請求額と小計と消費税額と合計が印刷されません。

    いかがでしたでしょうか。I言語はかなり簡単に早く作れるようにしましたが、それでも実際のシステム作りは。結構大変ですので、I言語を使わないととんでもなく時間がかかってしまいます。
    All Rights Reserved, Copyright (C) 2024-2024 Nobumichi Harasawa.