実践・自作会計ソフトを作る③

2024-12-22

GAS ツール プログラミング

B!

自営業な私は会計ソフトに金をかけたくない。だから会計ソフトを作るんだー!!の続きです

①、②はこちら↓ 今回はいよいよ中身に突入です。GASがある程度わかっている前提で話を進めます。

GASプロジェクトの準備とか

会計システムのスプレッドシートの「拡張機能」から「Apps Script」を起動し、適当なプロジェクト名を入力してください。

自分は「コード.gs」を「main.gs」に名前変更しました。好きな名前で良いです。そのままでも大丈夫です。

コードを見ると分かると思いますが、自分は定数定義をめっちゃします。見づらいなーと思った方はファイルを追加し、定数用と分けてもらった方が良いです。

自分はメインのファイルと定義用ファイルを分けたい派なので、デフォルトで存在する「コード.gs」を「main.gs」とし、新規スクリプトファイルを追加、「define.gs」を作成しました。

GAS的に分ける必要はありません。自分の書き方だととっても長くなってしまうので、定義用とメイン処理を分けています。他にもよく使う関数群を「lib.gs」に分けたりしていますが、今回はとりあえず「main.gs」にすべてまとめます。

自分の好きな書き方で構いません。

定数定義

早速ですがソースコードです。ファイル的には一纏めにしても良いですが、既に可読性が低いので定数部分と関数部分に分けて載せておきます。
// -----------------------------------------------------------------------------
// 定数.
// -----------------------------------------------------------------------------
const SheetID                   = '会計システムのシートID';

// -----------------------------------------------------------------------------
// シート名.
// -----------------------------------------------------------------------------
const SheetNameMain              = 'main';
const SheetNameDefine            = 'define';
const SheetNameFixAssList        = 'list';

const SheetNamePL                = 'PLTmp';             // 損益計算書.
const SheetNameBS                = 'BSTmp';             // 貸借対照表.
const SheetNameJournal           = 'JournalTmp';        // 仕訳帳.
const SheetNameGeneralLedger     = 'GeneralLedgerTmp';  // 総勘定元帳.
const SheetNameCash              = 'CashTmp';           // 現金出納帳.
const SheetNameDeposit           = 'DepositTmp';        // 預金出納帳. 
const SheetNameAccRec            = 'AccRecTmp';         // 売掛帳.
const SheetNameAccPay            = 'AccPayTmp';         // 買掛帳.
const SheetNameExp               = 'ExpTmp';            // 経費帳.
const SheetNameFixAss            = 'FixAssTmp';         // 固定資産台帳.
// -------------------------------------------------------------------------------------------------------
// mainシート.
// -------------------------------------------------------------------------------------------------------
const MainNowYear                 = 'C6';       // 現在の年度.
const MainGroup                   = 'C5';       // グループ名.
const MainAccount                 = 'I7';       // 口座情報.
const MainType                    = 'C11';      // 仕訳タイプ 収入・支出・振替.
const MainDate                    = 'C12';      // 日付.
const MainAnbun                   = 'C13';      // 家事按分.
const MainKind                    = 'C15';      // 仕訳科目.
const MainMeans                   = 'C16';      // 取引手段.
const MainAbout                   = 'C17';      // 摘要.
const MainPatner                  = 'C18';      // 取引先.
const MainCash                    = 'C19';      // 金額.
const MainTempID                  = 'G2';       // テンプレートシートID.
const MainOutputID                = 'G3';       // 出力先フォルダID.

const MainFuriDataStartY          = 14;         // 振替:データ開始Y.
const MainFuriKariX               = 5;          // 振替:借方X.
const MainFuriKariCashX           = 6;          // 振替:借方金額X.
const MainFuriKashiX              = 7;          // 振替:貸方X.
const MainFuriKashiCashX          = 8;          // 振替:貸方金額X.
const MainFuriAbout               = 'F12';      // 振替:摘要.
const MainFuriPather              = 'H12';      // 振替:取引先.

// 固定資産管理.
const MainFixAssID                = 'C26';      // 管理番号.
const MainFixAssType              = 'C27';      // 種類.
const MainFixAssName              = 'C28';      // 名称.
const MainFixAssAbout             = 'C29';      // 摘要.
const MainFixAssNum               = 'C30';      // 数量/面積.
const MainFixAssDate              = 'C31';      // 取得/売却日.
const MainFixAssUse               = 'C32';      // 共用日.
const MainFixAssCost              = 'C33';      // 取得価格.
const MainFixAssMethod            = 'C34';      // 償却方法.
const MainFixAssLife              = 'C35';      // 耐用年数(年).
const MainFixAssRate              = 'C36';      // 事業専用割合.

const MainFixAssGStartY           = 27;         // 固定資産管理:グローバルデータ開始Y.
const MainFixAssGEndY             = 30;         // 固定資産管理:グローバルデータ終了Y.
const MainFixAssGTagX             = 6;          // 固定資産管理:タグX.
const MainFixAssGenkaMulX         = 7;          // 固定資産管理:減価償却累計額X.
const MainFixAssHiyouX            = 8;          // 固定資産管理:今期減価償却費X.
const MainFixAssMulX              = 9;          // 固定資産管理:固定資産計X.
const MainFixAssCheckX            = 10;         // 固定資産管理:決算処理済みチェックX.

// 次期繰越メモ.
const MainGlobalStartY            = 55;         // データ開始Y.
const MainGlobalSheetNameX        = 2;          // シート名.
const MainGlobalDateX             = 4;          // 最終入力日.
const MainGlobalPrm0X             = 5;          // パラメータ0.
const MainGlobalPrm1X             = 6;          // パラメータ1.
const MainGlobalPrm2X             = 7;          // パラメータ2.
const MainGlobalPrm3X             = 8;          // パラメータ3.
const MainGlobalPrm4X             = 9;          // パラメータ4.
const MainGlobalIsTateX           = 10;         // 縦かどうか.
const MainGlobalIsSaveX           = 11;         // 保存するかどうか.    

const MainGlobalGenkinIncX        = 5;          // 現金/預金出納帳:収入合計.
const MainGlobalGenkinBalX        = 6;          // 現金/預金出納帳:残高.

const MainGlobalKashiLastDateX    = 5;          // 総勘定元帳:貸方最終入力日.
const MainGlobalSoukanKariBalX    = 6;          // 総勘定元帳:借方合計.
const MainGlobalSoukanKashiBalX   = 7;          // 総勘定元帳:貸方合計.
const MainGlobalSonekiRiX         = 8;          // 総勘定元帳【損益】:当期純利益.
const MainGlobalSonekiSonX        = 9;          // 総勘定元帳【損益】:当期純損失.

const MainGlobalKaiBalX           = 5;          // 買掛:残高
const MainGlobalKaiIncX           = 6;          // 買掛:貸方合計.
const MainGlobalUriBalX           = 7;          // 売掛:残高.
const MainGlobalUriIncX           = 8;          // 売掛:借方合計.

const MainGlobalKeihiGenkinBalX   = 5;          // 経費:現金合計.
const MainGlobalKeihOtherBalX     = 6;          // 経費:その他合計.

const MainGlobalFixAssGetCost     = 5;          // 固定資産台帳:取得金額.
const MainGlobalFixAssCash        = 6;          // 固定資産台帳:残金.
const MainGlobalFixAssNum         = 9;          // 固定資産台帳:残量数.
// -------------------------------------------------------------------------------------------------------
// defineシート.
// -------------------------------------------------------------------------------------------------------
const DefineIDX                   = 1;          // ID.
const DefineKindX                 = 3;          // 勘定科目.
const DefineCategoryX             = 4;          // 勘定科目のカテゴリ.
const DefineExpensesX             = 5;          // 経費になる勘定科目.
const DefineNowYearX              = 6;          // 会計年度で使用中の勘定科目.
const DefineSuppliersX            = 7;          // 取引先リスト.

const DefineStartY                = 2;          // データの開始Y.
// -------------------------------------------------------------------------------------------------------
// 損益計算書/貸借対照表.
// -------------------------------------------------------------------------------------------------------
const SonekiSheetName             = '損益計算書';
const TaisyakuSheetName           = '貸借対照表';
const KessanDate                  = 'D2';     // 決算期間.
const KessanGroup                 = 'A3';     // グループ・会社名.
const KessanKariX                 = 1;        // 費用.
const KessanKariCashX             = 2;        //
const KessanKashiX                = 3;        // 収益.
const KessanKashiCashX            = 4;

const TaisyakuKariX               = 1;
const TaisyakuMShisanCashX        = 2;        // 資産のマイナス.
const TaisyakuKariCashX           = 3;
const TaisyakuKashiX              = 4;
const TaisyakuKashiCashX          = 5;
// -------------------------------------------------------------------------------------------------------
// 仕訳帳.
// -------------------------------------------------------------------------------------------------------
const ShiwakeSheetName            = '仕訳帳';
const SiwakeYear                  = 'B3';     // 年度.
const ShiwakeMonthX               = 1;        // 月.
const ShiwakeDayX                 = 2;        // 日.
const ShiwakeAboutX               = 3;        // 摘要.
const ShiwakePageX                = 4;        // 元丁.
const ShiwakeKariX                = 5;        // 借方.
const ShiwakeKashiX               = 6;        // 貸方.
// -------------------------------------------------------------------------------------------------------
// 現金出納帳.
// -------------------------------------------------------------------------------------------------------
const GenkinSheetName             = '現金出納帳';
const GenkinYear                  = 'B3';     // 年度.
const GenkinMonthX                = 1;        // 月.
const GenkinDayX                  = 2;        // 日.
const GenkinAboutX                = 3;        // 摘要.
const GenkinInX                   = 4;        // 収入.
const GenkinOutX                  = 5;        // 支出.
const GenkinBalance               = 6;        // 残高.

const GenkinStartY                = 5;        // データ開始Y.
// -------------------------------------------------------------------------------------------------------
// 預金出納帳.
// -------------------------------------------------------------------------------------------------------
const YokinSheetName              = '預金出納帳';
const YokinYear                   = 'B4';     // 年度.
const YokinAccount                = 'E2';     // 口座情報.

const YokinStartY                 = 6;         // データ開始Y.
// -------------------------------------------------------------------------------------------------------
// 総勘定元帳.
// -------------------------------------------------------------------------------------------------------
const SoukanjouKamoku             = 'A2';       // 勘定科目.
const SoukanjouKariYear           = 'B4';       // 借方の年度.
const SoukanjouKashiYear          = 'G4';       // 貸方の年度.
const SoukanjouIDX                = 'J3';       // 総勘定元帳ID.

const SoukanjouMonthOffsX         = -2;         // 相手科目からのオフセット:月.
const SoukanjouDayOffsX           = -1;         // 相手科目からのオフセット:日.
const SoukanjouKariKamokuX        = 3;          // 借方:相手科目.
const SoukanjouKashiKamokuX       = 8;          // 貸方:相手科目.
const SoukanjouNumOffsX           = 1;          // 相手科目からのオフセット:仕分帳番号.
const SoukanjouCashOffsX          = 2;          // 相手科目からのオフセット:金額.

const SoukanjouTopX               = 1;          // 先頭X.
const SoukanjouEndX               = 10;         // 終端X.

const SoukanjouStartY             = 6;          // データの先頭Y.
// -------------------------------------------------------------------------------------------------------
// 経費帳.
// -------------------------------------------------------------------------------------------------------
const KeihiKamoku                 = 'E2';       // 経費科目.
const KeihiYear                   = 'B4';       // 年度.

const KeihiMonthX                 = 1;          // 月.
const KeihiDayX                   = 2;          // 日.
const KeihiAboutX                 = 3;          // 摘要.
const KeihiCashX                  = 4;          // 現金.
const KeihiOtherX                 = 5;          // その他.

const KeihiStartY                 = 6;          // データの先頭Y.
// -------------------------------------------------------------------------------------------------------
// 買掛・売掛帳.
// -------------------------------------------------------------------------------------------------------
const KakePatner                  = 'F2';       // 取引先.
const KakeYear                    = 'B3';       // 年度.

const KakeMonthX                  = 1;          // 月.
const KakeDayX                    = 2;          // 日.
const KakeAboutX                  = 3;          // 摘要.
const KakeKariX                   = 4;          // 借方.
const KakeKashiX                  = 5;          // 貸方.
const KakeBalanceX                = 6;          // 残高.

const KakeStartY                  = 5;          // データ開始Y.
// -------------------------------------------------------------------------------------------------------
// 固定資産一覧.
// -------------------------------------------------------------------------------------------------------
const FixListYear                 = 'A2';       // 開始年.

const FixListIDX                  = 1;          // 管理番号.
const FixListTypeX                = 2;          // 種類.
const FixListNameX                = 3;          // 名称.
const FixListGetDateX             = 4;          // 取得日.
const FixListUseDateX             = 5;          // 共用日.
const FixListCostX                = 6;          // 取得価格.
const FixListIsEndX               = 7;          // 償却済みか.

const FixListStartY               = 5;
// -------------------------------------------------------------------------------------------------------
// 固定資産台帳.
// -------------------------------------------------------------------------------------------------------
const FixAssName                  = 'D1';       // 名称.
const FixAssID                    = 'D2';       // 管理番号.
const FixAssType                  = 'D3';       // 種類.
const FixAssGetDate               = 'F1';       // 取得日.
const FixAssUseDate               = 'F2';       // 共用日.
const FixAssExRate                = 'F3';       // 専用割合.
const FixAssLife                  = 'H1';       // 耐用年数.
const FixAssMethod                = 'H2';       // 償却方法.
const FixAssRate                  = 'H3';       // 償却率.

const FixAssYearX                 = 1;          // 年.
const FixAssMonthX                = 2;          // 月.
const FixAssDayX                  = 3;          // 日.
const FixAssAbout                 = 4;          // 摘要.
const FixAssGetNum                = 5;          // 取得数量.
const FixAssGetCost               = 6;          // 取得原価.
const FixAssDelNum                = 7;          // 異動数量.
const FixAssDelCost               = 8;          // 異動価格.
const FixAssAmortized             = 9;          // 償却額.
const FixAssRestNum               = 10;         // 残数.
const FixAssRestCost              = 11;         // 残り価値.
const FixAssExpenses              = 12;         // 経費計上額.

const FicAssStartY                = 7;          // 
それぞれコメントにあるセルの位置やシート名、X・Yとある場合はRow(X)とColum(Y)の位置を定義しています。なんでこんな面倒なことをするかと思う方もいるかもしれないのですが、簡単に説明すると、こっちの方がメンテナンス性が高いからです。これならばテンプレートのフォーマットが変わった場合でもすぐに対応できるはずです。

修正する時にプログラムからセルを指定している箇所を特定するのってめんどくないですか?めんどくない人は定数定義しなくてもいいと思います。自分がこちらの方が修正しやすいというだけの理由です。これが絶対正しいわけではありません。むしろもっといい方法があればこっそり教えて下さい。

※前回のインターフェイスを考えるの部分でdefaultシートを作成していましたが、名前をdefineに変更しています。すみません...

新年度開始ボタンの内容

新年度開始時に必ず行う処理を考えます。

新年度を開始する際は、「仕訳帳」、「各種出納帳(今回は現金・預金を用意)」の新規作成、前年度の状況によって「総勘定元帳」の前年度繰越処理と新規作成、「経費シート」、「売掛帳」、「買掛帳」の削除、貸借・損益、減価償却費のリセットなどなどを行います。
// =============================================================================
// 会計システム.
// =============================================================================

// =============================================================================
// 新年度開始.
// =============================================================================
// -----------------------------------------------------------------------------
// 新年度開始をおしたときのエントリーポイント.
// -----------------------------------------------------------------------------
function CreateNewProject() {
  // シートの取得.
  let mainSheet = GetSheet( SheetNameMain );
  let defSheet = GetSheet( SheetNameDefine );
 
  // 年度の取得.
  let year = Number.parseInt( mainSheet.getRange( MainNowYear ).getValue() );

  let newSheet;
  let newDate = new Date( year, 0,1 );

  if ( Browser.msgBox('本当に新年度を開始してもよろしいですか?', Browser.Buttons.OK_CANCEL ) != 'ok' ) { return; }

  // 仕訳帳を作成.
  newSheet = CreateNewSheet( ShiwakeSheetName, SheetNameJournal );
  newSheet.getRange( SiwakeYear ).setValue( year + '年' );

  // 現金出納帳を作成.
  newSheet = CreateNewSheet( GenkinSheetName, SheetNameCash );
  newSheet.getRange( GenkinYear ).setValue( year + '年' );

  // 預金出納帳を作成.
  newSheet = CreateNewSheet( YokinSheetName, SheetNameDeposit );
  newSheet.getRange( YokinYear ).setValue( year + '年' );
  newSheet.getRange( YokinAccount ).setValue( mainSheet.getRange( MainAccount ).getValue() );

  // 総勘定元帳の作り直し、前期繰越.
  let maxY = GetLastRow( defSheet, DefineNowYearX ) + 1;
  for ( let i = 2; i < maxY; ++i ) {
    let kanjouSheet = GetSheet( '【' + defSheet.getRange( i, DefineNowYearX ).getValue() + '】総勘定元帳' );
    DeleteSheet( kanjouSheet );
    AddKanjou( defSheet.getRange( i, DefineNowYearX ).getValue(), newDate, 'null', 0, false );
  }

  // 経費シートの削除.
  maxY = GetLastRow( defSheet, DefineExpensesX ) + 1;
  for ( let i = 2; i < maxY; ++i ) {
    let keihiSheet = GetSheet( '【' + defSheet.getRange( i, DefineExpensesX ).getValue() + '】経費帳' );
    if ( keihiSheet !== null ) {
      DeleteSheet( keihiSheet );
    }
  }

  // 取引先売掛・買掛シート削除.
  maxY = GetLastRow( defSheet, DefineSuppliersX ) + 1;
  for ( let i = 2; i < maxY; ++i ) {
    let kakeSheet = GetSheet( '【' + defSheet.getRange( i, DefineSuppliersX ).getValue() + '】売掛帳' );
    if ( kakeSheet !== null ) {
      DeleteSheet( kakeSheet );
    }
    kakeSheet = GetSheet( '【' + defSheet.getRange( i, DefineSuppliersX ).getValue() + '】買掛帳' );
    if ( kakeSheet !== null ) {
      DeleteSheet( kakeSheet );
    }   
  }

  // 最終入力年月日をリセット.
  newDate = new Date( year - 1, 11, 31 );
  mainSheet.getRange( MainGlobalStartY,MainGlobalDateX,200,1 ).setValue( newDate );

  // 貸借・損益のリセット.
  DeleteSheet( GetSheet( SonekiSheetName ) );
  DeleteSheet( GetSheet( TaisyakuSheetName ) );
  SetGlobalParam( SonekiSheetName, MainGlobalPrm0X, 0 );
  SetGlobalParam( SonekiSheetName, MainGlobalPrm1X, 0 );
  SetGlobalParam( TaisyakuSheetName, MainGlobalPrm0X, 0 );
  SetGlobalParam( TaisyakuSheetName, MainGlobalPrm1X, 0 );

  // 今期減価償却額のリセット.
  mainSheet.getRange( MainFixAssGStartY,MainFixAssHiyouX,4,1 ).setValue(0); 

  // 固定資産の済をリセット.
  RangeClearSetPrm( mainSheet, MainFixAssCheckX, MainFixAssGStartY, 1, 4, '未' );

  return;
}


// =============================================================================
// 記帳.
// =============================================================================
// -----------------------------------------------------------------------------
// 総勘定元帳.
// 勘定科目名称, 日付, 相手科目, 金額, 借方か?.
// -----------------------------------------------------------------------------
function AddKanjou( kamokuName, date, aite, cash, isKari ) {

  let defSheet = GetSheet( SheetNameDefine );

  // 勘定科目検索.
  let kamokuID = Number.parseInt( GetDefineID( kamokuName ) );
  if ( kamokuID === -1 ) {
    // ID追加.
    let lastY = GetLastRow( defSheet, DefineNowYearX ) + 1;
    kamokuID = defSheet.getRange( lastY, DefineIDX ).getValue();
    defSheet.getRange( lastY, DefineNowYearX ).setValue( kamokuName );
  }
  
  // シート検索.
  let sheetName = '【' + kamokuName + '】総勘定元帳';
  let kanjouSheet = GetSheet( sheetName );
  if ( kanjouSheet === null ) {
    kanjouSheet = CopyTmplateSheet( SheetNameGeneralLedger, sheetName );
    // 年度を入力.
    kanjouSheet.getRange( SoukanjouKariYear ).setValue( date.getFullYear() + '年' );
    kanjouSheet.getRange( SoukanjouKashiYear ).setValue( date.getFullYear() + '年' );
    // 科目を入力.
    kanjouSheet.getRange( SoukanjouKamoku ).setValue( kamokuName );
    // IDを入力.
    kanjouSheet.getRange( SoukanjouIDX ).setValue( kamokuID );
    // パラメータ保存用.
    AddGlobalSheet( sheetName );
    // 第一パラメータの形式を修正.
    SetupParamType( sheetName, MainGlobalKashiLastDateX, 'yyyy/mm/dd');
    SetGlobalParam( sheetName, MainGlobalKashiLastDateX, new Date( date.getFullYear() - 1, 11, 31 ) );
    // 前期繰越記帳.
    let startDate = new Date( date.getFullYear(), 0,1 );
    let kariBal = GetGlobalParamInt( sheetName, MainGlobalSoukanKariBalX );
    let kashiBal = GetGlobalParamInt( sheetName, MainGlobalSoukanKashiBalX );
    let type = '';
    if ( kariBal > kashiBal ) {
      type = '資産';
    } else
    if ( kariBal < kashiBal ) {
      type = '負債';
    } else {
      switch ( GetKind( kamokuName ) ) {
      case '資産': type = '資産'; break;
      case '負債':
      case '純資産':
      case 'ー資産': type = '負債'; break;
      default:break;
      }
    }
    switch ( type ) {
    case '資産':
      kanjouSheet.insertRowsAfter( SoukanjouStartY, 1 );   // 列追加.
      // 月日入力.
      InputDate( kanjouSheet, startDate, SoukanjouStartY, SoukanjouKariKamokuX + SoukanjouMonthOffsX, SoukanjouKariKamokuX + SoukanjouDayOffsX );
      kanjouSheet.getRange( SoukanjouStartY, SoukanjouKariKamokuX ).setValue( '前期繰越' );
      kanjouSheet.getRange( SoukanjouStartY, SoukanjouKariKamokuX + SoukanjouCashOffsX ).setValue( GetGlobalParamInt( sheetName, MainGlobalSoukanKariBalX ) );
      // 罫線.
      CreateKanjouDefaultBorder( kanjouSheet, SoukanjouStartY );
      break;
    case '負債':
      kanjouSheet.insertRowsAfter( SoukanjouStartY, 1 );   // 列追加.
      // 月日入力.
      InputDate( kanjouSheet, startDate, SoukanjouStartY, SoukanjouKashiKamokuX + SoukanjouMonthOffsX, SoukanjouKashiKamokuX + SoukanjouDayOffsX );
      kanjouSheet.getRange( SoukanjouStartY, SoukanjouKashiKamokuX ).setValue( '前期繰越' );
      kanjouSheet.getRange( SoukanjouStartY, SoukanjouKashiKamokuX + SoukanjouCashOffsX ).setValue( GetGlobalParamInt( sheetName, MainGlobalSoukanKashiBalX ) );
      // 罫線.
      CreateKanjouDefaultBorder( kanjouSheet, SoukanjouStartY );
      break;
    default:break;
    }
  }

  // 
  if ( aite === 'null' ) { return; }

  // データの最終行を取得.
  let kariMax, kashiMax, inputX, inputY, balance;
  if ( isKari === true ) {
    // 借方の場合.
    inputX = SoukanjouKariKamokuX;
    balance = GetGlobalParamInt( sheetName, MainGlobalSoukanKariBalX );
  } else {
    // 貸方の場合.
    inputX = SoukanjouKashiKamokuX;
    balance = GetGlobalParamInt( sheetName, MainGlobalSoukanKashiBalX );
  }

  inputY = GetLastRow( kanjouSheet, inputX ) + 1;
  kariMax = GetLastRow( kanjouSheet, SoukanjouKariKamokuX ) + 1;
  kashiMax = GetLastRow( kanjouSheet, SoukanjouKashiKamokuX ) + 1;

  // 列の追加チェック.
  if ( kariMax === kashiMax ) {
    kanjouSheet.insertRowsAfter( inputY, 1 );   // 列追加.
  } else {
    if ( isKari === true ) {
      if ( kariMax > kashiMax ) {
        kanjouSheet.insertRowsAfter( inputY, 1 );   // 列追加.
      }
    } else {
      if ( kariMax < kashiMax ) {
        kanjouSheet.insertRowsAfter( inputY, 1 );   // 列追加.
      }
    }   
  }

  if ( inputY !== SoukanjouStartY ) {
    if ( kanjouSheet.getRange( (inputY - 1), inputX ).getValue() === '前期繰越' ) {
      kanjouSheet.getRange( inputY, inputX + SoukanjouNumOffsX ).setValue( 1 );
    } else {
      kanjouSheet.getRange( inputY, inputX + SoukanjouNumOffsX ).setValue( '〃' );
    }
  } else {
    kanjouSheet.getRange( inputY, inputX + SoukanjouNumOffsX ).setValue( 1 );
  }

  kanjouSheet.getRange( inputY, inputX ).setValue( aite );
  kanjouSheet.getRange( inputY, inputX + SoukanjouCashOffsX ).setValue( cash );

  // 月日入力.
  // 合計更新.
  // 最終入力日更新.
  balance += cash;
  if ( isKari === true ) {
    InputDateSelect( kanjouSheet, date, GetGlobalParam( sheetName, MainGlobalDateX ),
      inputY, inputX + SoukanjouMonthOffsX, inputX + SoukanjouDayOffsX );
    SetGlobalParam( sheetName, MainGlobalSoukanKariBalX, balance );
    SetGlobalParam( sheetName, MainGlobalDateX, date );
  } else {
    InputDateSelect( kanjouSheet, date, GetGlobalParam( sheetName, MainGlobalKashiLastDateX ),
      inputY, inputX + SoukanjouMonthOffsX, inputX + SoukanjouDayOffsX );
    SetGlobalParam( sheetName, MainGlobalSoukanKashiBalX, balance );
    SetGlobalParam( sheetName, MainGlobalKashiLastDateX, date );
  }

  // 罫線.
  CreateKanjouDefaultBorder( kanjouSheet, inputY );

  return;
}


// =============================================================================
// util.
// =============================================================================
// -----------------------------------------------------------------------------
// シート名から保存用パラメータのY取得.
// -----------------------------------------------------------------------------
function GetGlobalY( sheetName ) {
  let mainSheet = GetSheet( SheetNameMain );
  let maxY = GetLastRow( mainSheet, MainGlobalSheetNameX );
  let ranges = mainSheet.getRange( MainGlobalStartY,MainGlobalSheetNameX,maxY,1 ).createTextFinder( sheetName ).findAll();

  if ( ranges.length !== 0 ) {
    return ranges[0].getRow();
  }

  // 見つからなかった.
  Browser.msgBox( '「' + sheetName + '」は作成されていないシートです', Browser.Buttons.OK );

  return -1;
}
// -----------------------------------------------------------------------------
// シートを追加したら呼ぶ処理.
// -----------------------------------------------------------------------------
function AddGlobalSheet( sheetName ) {
  let mainSheet = GetSheet( SheetNameMain );
  let maxY = GetLastRow( mainSheet, MainGlobalSheetNameX );
  let ranges = mainSheet.getRange( MainGlobalStartY,MainGlobalSheetNameX,maxY,1 ).createTextFinder( sheetName ).findAll();

  if ( ranges.length !== 0 ) {
    // 存在するのでパス.
    return;
  }

  // シート名を追加する.
  mainSheet.getRange( (maxY + 1), MainGlobalSheetNameX ).setValue( sheetName );
  return;
}
// -----------------------------------------------------------------------------
// パラメータの型を変更.
// -----------------------------------------------------------------------------
function SetupParamType( sheetName, prmNum, format ) {
  let indexY = GetGlobalY( sheetName );
    GetSheet( SheetNameMain ).getRange( indexY, prmNum ).setNumberFormat( format );
  return;
}
// -----------------------------------------------------------------------------
// パラメータ取得(無変換).
// -----------------------------------------------------------------------------
function GetGlobalParam( sheetName, idxX ) {
  let indexY = GetGlobalY( sheetName );
  if ( indexY === -1 ) { return -1; }
  return GetSheet( SheetNameMain ).getRange( indexY, idxX ).getValue();
}
// -----------------------------------------------------------------------------
// パラメータ取得(整数).
// -----------------------------------------------------------------------------
function GetGlobalParamInt( sheetName, idxX ) {
  return Number.parseInt( GetGlobalParam(sheetName, idxX) );
}
// -----------------------------------------------------------------------------
// パラメータ取得(小数).
// -----------------------------------------------------------------------------
function GetGlobalParamFloat( sheetName, idxX ) {
  return Number.parseFloat( GetGlobalParam(sheetName, idxX) );
}
// -----------------------------------------------------------------------------
// パラメータ取得(最終入力日).
// -----------------------------------------------------------------------------
function GetGlobalLastDate( sheetName ) {
  return GetGlobalParam( sheetName, MainGlobalDateX );
}
// -----------------------------------------------------------------------------
// 保存用パラメータを入力.
// -----------------------------------------------------------------------------
function SetGlobalParam( sheetName, idxX, prm ) {
  let indexY = GetGlobalY( sheetName );
  if ( indexY === -1 ) { return -1; }
  GetSheet( SheetNameMain ).getRange( indexY, idxX ).setValue( prm );
  return;
}


// -----------------------------------------------------------------------------
// 現在のスプレッドシートの中の指定の名前のシートを取得.
// -----------------------------------------------------------------------------
function GetSheet( sheetName ) {
  return SpreadsheetApp.getActive().getSheetByName( sheetName );
}
// -----------------------------------------------------------------------------
// 新規シートの作成(コピーテンプレから) / 同じシートがあれば削除Ver.
// -----------------------------------------------------------------------------
function CreateNewSheet( newSheetName, copySheetName ) {
  let newSheet = GetSheet( newSheetName );
  if ( newSheet !== null ) {
    // シートを削除する.
    DeleteSheet( newSheet );
  }
  newSheet = CopyTmplateSheet( copySheetName, newSheetName );
  return newSheet;
}
// -----------------------------------------------------------------------------
// シートのコピー作成&リネーム.
// -----------------------------------------------------------------------------
function CopyTmplateSheet( copySheetName, newSheetName ) {

  let mainSheet = GetSheet( SheetNameMain );

  var copy = SpreadsheetApp.openById( mainSheet.getRange( MainTempID ).getValue() ).getSheetByName( copySheetName );
  if ( copy === null ) { return null; }// 失敗.
  
  var newSheet = copy.copyTo( SpreadsheetApp.getActive() );
  
  if ( newSheet === null ) { return null; }//失敗.
  
  // リネーム.
  newSheet.setName( newSheetName );
  
  return newSheet;
}
// -----------------------------------------------------------------------------
// シートを削除.
// -----------------------------------------------------------------------------
function DeleteSheet( sheet ) {
  if ( sheet === null ) { return; }
  SpreadsheetApp.getActive().deleteSheet( sheet );
  return;
}
// -----------------------------------------------------------------------------
// 指定した列のデータが入力されている最終列を取得する.
// -----------------------------------------------------------------------------
function GetLastRow( sheet, idx ) {
  return sheet.getRange(sheet.getMaxRows(), idx).getNextDataCell(SpreadsheetApp.Direction.UP).getRow();
}
// -----------------------------------------------------------------------------
// 指定した範囲をクリアして値をセットする.
// -----------------------------------------------------------------------------
function RangeClearSetPrm( sheet, startX, startY, countX, countY, prm ) {
  let rangeX, rangeY;
  
  // X方向.
  if ( countX === 0 ) {
    rangeX = GetLastColL( sheet, startY ) + 1;
  } else {
    rangeX = countX;
  }

  // Y方向.
  if ( countY === 0 ) {
    rangeY = GetLastRow( sheet, startX ) + 1;
  } else {
    rangeY = countY;
  }

  sheet.getRange( startY, startX, rangeY, rangeX ).setValue( prm );
  return;
}
いきなりげんなりする量になってますが・・・ちょっとぶっ飛ばしていきます。

Browser.msgBox(〜
22行目:
新年度開始しても良いか確認します。自分が間違えて押した事があるのでw

24行目〜35行目:
仕訳帳、現金出納帳、預金出納帳の作成 これらは年度開始毎に新たに作り直しています。

// 総勘定元帳の作り直し、前期繰越.
  let maxY = GetLastRow( defSheet, DefineNowYearX ) + 1;
  for ( let i = 2; i < maxY; ++i ) {
    let kanjouSheet = GetSheet( '【' + defSheet.getRange( i, DefineNowYearX ).getValue() + '】総勘定元帳' );
    DeleteSheet( kanjouSheet );
    AddKanjou( defSheet.getRange( i, DefineNowYearX ).getValue(), newDate, 'null', 0, false );
  }
37行目~43行目
ここでは前年度までにdefineシートに保存している勘定科目の一覧から総勘定元帳の作り直しをしています。

AddKanjou()内では前年度繰越処理はもちろん、仕訳処理が発生した際の処理もすでに書いています。

※仕訳処理が発生すると、それぞれのシートで計算に使う合計値などをmainシートに保存し、前年度繰越処理や月毎の締め処理に使用しています。(util以下のパラメータ設定、取得を参照)

// 経費シートの削除.
  maxY = GetLastRow( defSheet, DefineExpensesX ) + 1;
  for ( let i = 2; i < maxY; ++i ) {
    let keihiSheet = GetSheet( '【' + defSheet.getRange( i, DefineExpensesX ).getValue() + '】経費帳' );
    if ( keihiSheet !== null ) {
      DeleteSheet( keihiSheet );
    }
  }

  // 取引先売掛・買掛シート削除.
  maxY = GetLastRow( defSheet, DefineSuppliersX ) + 1;
  for ( let i = 2; i < maxY; ++i ) {
    let kakeSheet = GetSheet( '【' + defSheet.getRange( i, DefineSuppliersX ).getValue() + '】売掛帳' );
    if ( kakeSheet !== null ) {
      DeleteSheet( kakeSheet );
    }
    kakeSheet = GetSheet( '【' + defSheet.getRange( i, DefineSuppliersX ).getValue() + '】買掛帳' );
    if ( kakeSheet !== null ) {
      DeleteSheet( kakeSheet );
    }   
  }
45行目~65行目:
経費帳、買掛・売掛帳は年度毎作成するので削除します。

// 貸借・損益のリセット.
  DeleteSheet( GetSheet( SonekiSheetName ) );
  DeleteSheet( GetSheet( TaisyakuSheetName ) );
  SetGlobalParam( SonekiSheetName, MainGlobalPrm0X, 0 );
  SetGlobalParam( SonekiSheetName, MainGlobalPrm1X, 0 );
  SetGlobalParam( TaisyakuSheetName, MainGlobalPrm0X, 0 );
  SetGlobalParam( TaisyakuSheetName, MainGlobalPrm1X, 0 );
71行目~77行目:
貸借対照表、損益計算書があれば削除し、保存用パラメータをリセットします。

// 今期減価償却額のリセット.
  mainSheet.getRange( MainFixAssGStartY,MainFixAssHiyouX,4,1 ).setValue(0);
79、80行目:
今期の減価償却額をリセットします。その後で固定資産管理のチェックもリセットしています。

util(ユーティリティ)ではとりあえず何度も使う処理をまとめています。関数内で失敗した場合、特に何の対応していないので、ダイアログを出すなどするとデバッグも楽かもしれません。

新年度開始の実行結果

ここまでできたら「新年度開始」ボタンに関数「CreateNewProject」を割り当てます。

割り当てが出来たらクリックしてみてください。実行後、仕訳帳、現金出納帳、預金出納帳が出来、パラメータがリセットされれば成功です。

クリア(clear)ボタンの内容

もうすでに長くなってますが…まだまだ処理が残ってるのでクリアボタンも作ります!よ!!
// -----------------------------------------------------------------------------
// clearをおしたときのエントリーポイント.
// -----------------------------------------------------------------------------
function Clear() {
//  return;
  // シートの取得.
  let mainSheet = GetSheet( SheetNameMain );
  let defSheet = GetSheet( SheetNameDefine );
  let listSheet = GetSheet( SheetNameFixAssList );
  let newSheet;
  
  // 年度の取得.
  let year = Number.parseInt( mainSheet.getRange( MainNowYear ).getValue() );

  DeleteSheet( GetSheet( SonekiSheetName ) );
  DeleteSheet( GetSheet( TaisyakuSheetName ) );
  DeleteSheet( GetSheet( ShiwakeSheetName ) );
  DeleteSheet( GetSheet( GenkinSheetName ) );
  DeleteSheet( GetSheet( YokinSheetName ) );

  // defineの使用科目列を一旦リセット.
  let maxY = GetLastRow( defSheet, DefineNowYearX ) + 1;
  for ( let i = 2; i < maxY; ++i ) {
    let kanjouSheet = GetSheet( '【' + defSheet.getRange( i, DefineNowYearX ).getValue() + '】総勘定元帳' );
    DeleteSheet( kanjouSheet );
  }
  RangeClear( defSheet, DefineNowYearX, 2, 1, 0 );

  // 固定資産の済をリセット.
  RangeClearSetPrm( mainSheet, MainFixAssCheckX, MainFixAssGStartY, 1, 4, '未' );
  mainSheet.getRange( MainFixAssGStartY,MainFixAssGenkaMulX,4,3 ).setValue(0);

  // 固定資産リスト新規作成・固定資産台帳削除.
  maxY = GetLastRow( listSheet, FixListIDX ) + 1;
  for ( let i = FixListStartY; i < maxY; ++i ) {
    let fixassSheet = GetSheet('【' + listSheet.getRange( i, FixListIDX ).getValue() + '】固定資産台帳');
    DeleteSheet( fixassSheet );
  }
  newSheet = CreateNewSheet( SheetNameFixAssList, 'FixAssListTmp' );
  newSheet.getRange( FixListYear ).setValue( year + '年~' );

  // 経費シートの削除.
  maxY = GetLastRow( defSheet, DefineExpensesX ) + 1;
  for ( let i = 2; i < maxY; ++i ) {
    let keihiSheet = GetSheet( '【' + defSheet.getRange( i, DefineExpensesX ).getValue() + '】経費帳' );
    DeleteSheet( keihiSheet );
  }

  // 取引先売掛・買掛シート削除.
  maxY = GetLastRow( defSheet, DefineSuppliersX ) + 1;
  for ( let i = 2; i < maxY; ++i ) {
    let keihiSheet = GetSheet( '【' + defSheet.getRange( i, DefineSuppliersX ).getValue() + '】売掛帳' );
    DeleteSheet( keihiSheet );
    keihiSheet = GetSheet( '【' + defSheet.getRange( i, DefineSuppliersX ).getValue() + '】買掛帳' );
    DeleteSheet( keihiSheet );
  }

  // 最終入力年月日をリセット.
  let newDate = new Date( 1999, 11, 31 );
  mainSheet.getRange( MainGlobalStartY,MainGlobalDateX,200,1 ).setValue( newDate );

  // パラメータリセット.
  mainSheet.getRange( MainGlobalStartY,MainGlobalPrm0X,200,4 ).setValue(0).setNumberFormat( '[$¥-411]#,##0' );
  mainSheet.getRange( MainGlobalStartY,MainGlobalPrm4X,200,1 ).setValue(0);
  mainSheet.getRange( MainGlobalStartY+4,MainGlobalSheetNameX,200,1 ).clear();
  return;
}
// -------------------------------------------------------------------------------------------------------
// 指定範囲をクリアする.
// -------------------------------------------------------------------------------------------------------
function RangeClear( sheet, startX, startY, countX, countY ) {
  
  let rangeX, rangeY;
  
  // X方向.
  if ( countX === 0 ) {
    rangeX = GetLastColL( sheet, startY ) + 1;
  } else {
    rangeX = countX;
  }

  // Y方向.
  if ( countY === 0 ) {
    rangeY = GetLastRow( sheet, startX ) + 1;
  } else {
    rangeY = countY;
  }

  sheet.getRange( startY, startX, rangeY, rangeX ).clearContent();
  return;
}
まあなんてことはない、今あるシートを全削除して固定資産管理リストも作り直します。

ツールの開発が終了したら、5行目のコメントアウトを外せば万が一クリアボタンを押しても処理が通りません。(もしくはボタン自体を消すか)

クリアボタンの実行結果

こんな状態なら成功です。

まとめ

今回の処理作成で、総勘定元帳の作成処理をついでに実装しています。内容については改めて解説していきたいと思います。つづく!



ブログランキング・にほんブログ村へ

Translate

魔王と愉快な仲間

このブログを検索

ラベル

Blogger (7) FX (1) GAS (14) Utility (1) ゲーム (1) ツール (10) プログラミング (20) レポート (2) 移住 (3) 金策 (9) 土壌 (2) 独り言 (5) 読み物 (21) 農業 (3)

ブログ アーカイブ

メッセージ

名前

メール *

メッセージ *

Powered by Blogger.

フリー写真素材ぱくたそ

QooQ