第529話:PayPal業務のサブルーチン化

2017年4月3日

経理工程の独立

「独立したサブルーチン・プロセス」として『PayPal 請求フロー』を準備しておくと、とても便利です。

ワークフローシステム内の様々なビジネスフローから呼び出すことができるので、プロセスオーナーは、メインのビジネスフローの設計やメンテナンスに注力することができます。

下流側の経理部門の視点で言っても、複数のビジネスフローを区別なく処理できるため、効率よい業務をこなせるようになるでしょう。(ただし上流への関与は減る傾向になります)。また、ここ1・2年の変化が極めて激しい経理システム(※)にあって、「一元的に管理メンテナンスしたい」というニーズもあります。

※「クラウド会計」「銀行API」「会計BPO」など


PayPal請求書の処理

以下の業務プロセス定義(ワークフロー・アプリ)は、PayPal と自動連携する『PayPal 請求プロセス』です。

「PayPal REST API」、具体的には「PayPal Invoicing API」を通じて、ワークフローシステム側から様々なリクエストが行われます。つまり、
  • PayPal 側に『PayPal請求書』を生成させ、
  • PayPal から『PayPal請求書』を送信させ、
  • PayPal に対して『PayPal請求書』の決済状況を確認する
という仕組みになっています。(直接 PayPal にログインする機会は減ることになります)

[PayPal請求プロセス]


サブプロセス化の意義

前回記事、『第528話:自動工程で PayPal ステータスの自動確認』のプロセス図から、PayPal請求と関係ない工程を削ぎ落したプロセスとも言えます。

すなわち、この「PayPal請求プロセス」は、製造部門や販売部門のフローが完了した案件の案件データを受信することで、自動的に開始されることが前提となっています。

たしかに業務プロセス同士を接続する部分については、その設定に「慣れ」が必要かもしれません。しかし、送受信するデータ項目に変更がない限り設定変更する必要はなく、それぞれの業務プロセスで機動力をもって改善活動に取り組むことができるようになります。

※「単価」「数量」「請求先のメールアドレス」などのデータを HTTP の POST メソッドで送信します。WebデザイナやWebプログラマなど、Web フォームからデータ送信する仕組みを作ったことがある方なら、それほど難しいテクノロジーではありません。

参考マニュアル) M411: “納品プロセス” から “請求プロセス” が自動開始されるように設定する

経理視点での業務効率化

なお、このフローでは会計システムに登録すべき「振替伝票CSV」を自動生成させる「スクリプト工程」が用意されています。

ただ、そこで生成されるべき「振替伝票CSV」は、各社が採用している会計システムや会計基準によって異なるため、セットされるべき生成スクリプトもオリジナルなものになってしまうでしょう。この例では、売上高を按分計上すべき月について「計上開始月」と「按分月数」が上流プロセスから引き渡される前提で、『MFクラウド会計』に売上高を登録する業務を効率化しています。

ちなみに『MFクラウド会計』であれば、(『MFクラウド会計』自身も)、『PayPalの入金決済状況』を直接認知します。(OAuth連携が可能です)

したがって、ワークフローシステムである『Questetra』が、会計システムである『MFクラウド会計』に対して、決済システム『PayPal』の決済状況を伝える必要はありません。(2016年の「みずほ銀行」に始まった「銀行API」と同様の仕組みです)

<スクリプト工程「Generate CSV for Accounting」の設定例>
// Sales Accounting (ver. 20170329)
// (c) 2017, Questetra, Inc. (the MIT License)

//// == ワークフローデータの参照 / Data Retrieving ==
var contractName = processInstance.getProcessInstanceTitle() + "";
var invoiceTag = data.get( "q_billingBusinessName" ) + "";

var dateOfPayment = data.get( "q_paymentTermDueDate" );
// instanceof com.questetra.bpms.util.AddableDate *Manual#M230
var dateOfInvoice = data.get( "q_invoiceDate" );
// instanceof com.questetra.bpms.util.AddableDate *Manual#M230
var amountOfInvoice = data.get( "q_totalAmount" ) - 0;
var cardFee = parseInt( amountOfInvoice * 0.039 ) + 40; // 3.9%+40円

var dateOfInitialSales = data.get( "q_salesBookStartMonth" );
// instanceof com.questetra.bpms.util.AddableDate *Manual#M230
var categoryOfInitialSales = ""; // 勘定補助科目名
var amountOfInitialSales = 0; // 按分対象外の売上高(初月計上)

var startMonthOfRunningSales = data.get( "q_salesBookStartMonth" );
// instanceof com.questetra.bpms.util.AddableDate *Manual#M230
var categoryOfRunningSales = "SaaS(オプション含)"; // 勘定補助科目名
var countOfRunningSales = data.get( "q_itemQuantity" ) - 0;
var amountOfRunningSales = data.get( "q_totalAmount" ) - 0;


//// == 演算 / Calculating ==
// <slip csv record sample> (16 cols)
// "1234501","2016/12/01","売掛金","","対象外","","3334","売上高","SaaS(オプション含)","課税売上 8%","","3334","2016-12 @ AAA corp","","",""
// "1234502","2017/01/01","前受金","","対象外","","3333","売上高","SaaS(オプション含)","課税売上 8%","","3333","2017-01 @ AAA corp","","",""
// "1234503","2017/02/01","前受金","","対象外","","3333","売上高","SaaS(オプション含)","課税売上 8%","","3333","2017-02 @ AAA corp","","",""
// "1234504","2016/12/31","普通預金","XXX銀行","対象外","","10000","売掛金","","対象外","","3334","2016-11 # AAA corp","","","未実現"
// "1234504","2016/12/31","","","","","","前受金","","対象外","","6666","2016-11 # @ AAA corp","","",""

var accountingDateFormat = new java.text.SimpleDateFormat( "yyyy/MM/dd" );
var yearMonthDateFormat = new java.text.SimpleDateFormat( "yyyy-MM" );

var slipTsv = "伝票番号\t取引日\t";
slipTsv += "借方勘定科目\t借方補助科目\t借方税区分\t借方部門\t借方金額(円)\t";
slipTsv += "貸方勘定科目\t貸方補助科目\t貸方税区分\t貸方部門\t貸方金額(円)\t";
slipTsv += "摘要\t仕訳メモ\tタグ\tMF仕訳タイプ\n";

var subnum = 1;
var receivableTotal = 0; // 売掛金の額の計算
var receivedTotal = 0;   // 前受金の額の計算


/// Sales Records
// Before Payment: "売掛金 1000 / 売上高 1000"
// After Payment:  "前受金 1000 / 売上高 1000"

if( amountOfInitialSales !== 0 ){
  if( dateOfInitialSales.before( dateOfPayment ) ){
    slipTsv += processInstance.getProcessInstanceId() + ("00" + subnum).slice(-2) + "\t";
    slipTsv += accountingDateFormat.format( dateOfInitialSales ) + "\t";
    slipTsv += "売掛金" + "\t" + "\t" + "対象外" + "\t" + "\t" + amountOfInitialSales + "\t";
    slipTsv += "売上高" + "\t" + categoryOfInitialSales + "\t" + "課税売上 8%" + "\t" + "\t" + amountOfInitialSales + "\t";
    slipTsv += yearMonthDateFormat.format( dateOfInitialSales ) + " @ " + contractName  + "\t" + "\t" + invoiceTag + "\t";
    slipTsv += "\n";
    receivableTotal += amountOfInitialSales;
  }else{ // rare case
    slipTsv += processInstance.getProcessInstanceId() + ("00" + subnum).slice(-2) + "\t";
    slipTsv += accountingDateFormat.format( dateOfInitialSales ) + "\t";
    slipTsv += "前受金" + "\t" + "\t" + "対象外" + "\t" + "\t" + amountOfInitialSales + "\t";
    slipTsv += "売上高" + "\t" + categoryOfInitialSales + "\t" + "課税売上 8%" + "\t" + "\t" + amountOfInitialSales + "\t";
    slipTsv += yearMonthDateFormat.format( dateOfInitialSales ) + " @ " + contractName  + "\t" + "\t" + invoiceTag + "\t";
    slipTsv += "\n";
    receivedTotal += amountOfInitialSales;
  }
  subnum++;
}

if( amountOfRunningSales !== 0 ){
  var amountOfAfterSecond = Math.floor( amountOfRunningSales / countOfRunningSales );
  var amountOfFirst = amountOfRunningSales - amountOfAfterSecond * (countOfRunningSales - 1);
  for( var i = 0; i < countOfRunningSales; i++ ){
    var tmp = new com.questetra.bpms.util.AddableDate( startMonthOfRunningSales.addMonths( i ).getTime() );
    if( tmp.before( dateOfPayment ) ){
      slipTsv += processInstance.getProcessInstanceId() + ("00" + subnum).slice(-2) + "\t";
      slipTsv += accountingDateFormat.format( tmp ) + "\t";
      if( i === 0 ){
        slipTsv += "売掛金" + "\t" + "\t" + "対象外" + "\t" + "\t" + amountOfFirst + "\t";
        slipTsv += "売上高" + "\t" + categoryOfRunningSales + "\t" + "課税売上 8%" + "\t" + "\t" + amountOfFirst + "\t";
        receivableTotal += amountOfFirst;
      }else{
        slipTsv += "売掛金" + "\t" + "\t" + "対象外" + "\t" + "\t" + amountOfAfterSecond + "\t";
        slipTsv += "売上高" + "\t" + categoryOfRunningSales + "\t" + "課税売上 8%" + "\t" + "\t" + amountOfAfterSecond + "\t";
        receivableTotal += amountOfAfterSecond;
      }
      slipTsv += yearMonthDateFormat.format( tmp ) + " @ " + contractName  + "\t" + "\t" + invoiceTag + "\t";
      slipTsv += "\n";
    }else{
      slipTsv += processInstance.getProcessInstanceId() + ("00" + subnum).slice(-2) + "\t";
      slipTsv += accountingDateFormat.format( tmp ) + "\t";
      if( i === 0 ){
        slipTsv += "前受金" + "\t" + "\t" + "対象外" + "\t" + "\t" + amountOfFirst + "\t";
        slipTsv += "売上高" + "\t" + categoryOfRunningSales + "\t" + "課税売上 8%" + "\t" + "\t" + amountOfFirst + "\t";
        receivedTotal += amountOfFirst;
      }else{
        slipTsv += "前受金" + "\t" + "\t" + "対象外" + "\t" + "\t" + amountOfAfterSecond + "\t";
        slipTsv += "売上高" + "\t" + categoryOfRunningSales + "\t" + "課税売上 8%" + "\t" + "\t" + amountOfAfterSecond + "\t";
        receivedTotal += amountOfAfterSecond;
      }
      slipTsv += yearMonthDateFormat.format( tmp ) + " @ " + contractName  + "\t" + "\t" + invoiceTag + "\t";
      slipTsv += "\n";
    }
  subnum++;
  }
}

/// Bank Records
// amountOfInvoice == receivableTotal + receivedTotal
// ( "CashIn" ==  amountOfInvoice - cardFee )

slipTsv += processInstance.getProcessInstanceId() + ("00" + subnum).slice(-2) + "\t";
slipTsv += accountingDateFormat.format( dateOfPayment ) + "\t";
slipTsv += "当座預金" + "\t" + "PayPal" + "\t" + "対象外" + "\t" + "\t" + (amountOfInvoice - cardFee) + "\t";
slipTsv += "売掛金" + "\t" + "\t" + "対象外" + "\t" + "\t" + receivableTotal + "\t";
slipTsv += yearMonthDateFormat.format( dateOfInvoice ) + " # " + contractName  + "\t" + "\t" + invoiceTag + "\t" + "未実現";
slipTsv += "\n";
if( receivedTotal > 0 ){
  slipTsv += processInstance.getProcessInstanceId() + ("00" + subnum).slice(-2) + "\t";
  slipTsv += accountingDateFormat.format( dateOfPayment ) + "\t";
  slipTsv += "\t" + "\t" + "\t" + "\t" + "\t";
  slipTsv += "前受金" + "\t" + "\t" + "対象外" + "\t" + "\t" + receivedTotal + "\t";
  slipTsv += yearMonthDateFormat.format( dateOfInvoice ) + " # " + contractName  + "\t" + "\t" + "\t" + "未実現";
  slipTsv += "\n";
}
if( cardFee > 0 ){
  slipTsv += processInstance.getProcessInstanceId() + ("00" + subnum).slice(-2) + "\t";
  slipTsv += accountingDateFormat.format( dateOfPayment ) + "\t";
  slipTsv += "支払手数料" + "\t" + "カード手数料(売上)" + "\t" + "非課税仕入" + "\t" + "\t" + cardFee + "\t";
  slipTsv += "\t" + "\t" + "\t" + "\t" + "\t";
  slipTsv += yearMonthDateFormat.format( dateOfInvoice ) + " # " + contractName  + "\t" + "\t" + "\t" + "未実現";
  slipTsv += "\n";
}


//// == ワークフローデータへの代入 / Data Updating ==
slipTsv = slipTsv.slice(0, -1); // remove "\n" code at the end of tsv
retVal.put( "q_slipTsv", slipTsv );
// Next to Converter (Tsv String to Excel-CSV File) *Manual#M415

[PayPal請求プロセス:「1. 請求データCheck」画面]

<データ項目一覧画面>



[雛形ダウンロード (無料)]
<類似プロセス>
≪関連記事≫

[英文記事 (English Entry) ]

0 件のコメント :

コメントを投稿