yonet77的な雑記帳

日々思いついたネタなどを書き留めておきます

Force.comでのJSON Support -ApexコントローラのRemoteActionを添えて-(その後)

以前、Force.comでのJSON Support - yonet77的な雑記帳にて、管理パッケージ内にあるカスタムオブジェクトの日付項目をJSON.deserializeできない...ということを書きました。
うん、もう覚えてないよねw


ことの発端は、Summer '12 になった直後に、JSON.deserialize の挙動がおかしくなったことでした。

でも、その1週間後くらいには直ってたので、ヨカッタヨカッタと思ったところで、もう1つふと思い出しました。


そう、管理パッケージ内のカスタムオブジェクトの日付項目を含めてJSON.deserializeするとエラーになってた件です。
 ↓

FATAL_ERROR System.JSONException: Cannot deserialize instance of date from VALUE_STRING value 2011-12-30


今回の修正で、挙動が変わったかもしれないッ・・・!
ということで、レッツトライ。

こんなコードを走らせてみました。

Type objType = Type.forName('gii__SalesOrder__c');    	
String paramString = '{"gii__RequiredDate__c":"2011-12-30", "gii__Released__c":true, "Phase__c":"ご来店", "Remarks__c":"ABCDEFGHIJKLMN,4444aaa"}';
gii__SalesOrder__c testSO = (gii__SalesOrder__c)JSON.deserialize(paramString, objType);
System.debug('** testSO : ' + testSO);

14:21:46.132 (14132484000)|USER_DEBUG|[172]|DEBUG|** testSO : gii__SalesOrder__c:{gii__RequiredDate__c=2011-12-30 00:00:00, Remarks__c=ABCDEFGHIJKLMN,4444aaa, Phase__c=ご来店, gii__Released__c=true}


おや・・?なんか日付もちゃんとdeserializeされてるじゃないですか!
何やらパッケージ管理下にあるカスタムオブジェクトの日付項目も問題なくJSON.deserializeを使えるようになってましたー。
もちろん、これも動きました。↓

Type objType = Type.forName('List<gii__SalesOrder__c>');    	
String paramString = '[{"gii__RequiredDate__c":"2011-12-30", "gii__Released__c":true, "Phase__c":"ご来店", "Remarks__c":"ABCDEFGHIJKLMN,4444aaa"}]';
List<gii__SalesOrder__c> testSOs = (List<gii__SalesOrder__c>)JSON.deserialize(paramString, objType);
System.debug('** testSOs : ' + testSOs);

14:57:01.629 (11629374000)|USER_DEBUG|[176]|DEBUG|** testSOs : (gii__SalesOrder__c:{gii__RequiredDate__c=2011-12-30 00:00:00, Remarks__c=ABCDEFGHIJKLMN,4444aaa, Phase__c=ご来店, gii__Released__c=true})

とりあえず、思った通りの挙動になったみたいで良かったです。
ではまた次回(※未定)!

Glovia Order Management (on Salesforce) を使ってみようか (9)

久々の更新です。今回はgOMネタで。
Ver5.0 あたり(?)から追加された「買掛請求書」をちょいとイジッてみましょうか。

買掛請求書って?

サプライヤから送付された請求書で、「いついつまでにおいくら万円を支払ってね」といった内容を処理する感じでしょうか。
そんなわけで、gOMでは
 購買オーダー発行 → 購買受入
の後にやってくる、という想定で作られています。(そうでないケースにも対応可能ですが、大半はこの流れかと。)
そんなわけで、購買受入後という前提で話を続けます。

買掛請求書の処理

1. 買掛請求書の登録
サプライヤから届いた請求書をgOMに登録します。

f:id:yonet77:20120509212508p:plain


2. 購買オーダー受入を検収
買掛請求書を登録した後は、このサプライヤに対する購買受入を消し込みます。この買掛請求書が、何を買ったものに対する請求なのかを紐付ける作業となります。
買掛請求書画面の「購買オーダー受入を検収」ボタンから移動します。

f:id:yonet77:20120509213030p:plain


この画面で紐付けしてない購買受入を指定して、買掛請求書と紐付けします。これは完全に手で消し込んでいく作業となります。
もちろん、購買受入は複数紐付けできます。一度保存してから、「購買オーダー受入を検収」ボタンをクリックして、この画面に戻って再度紐付けしていきます。

f:id:yonet77:20120509213230p:plain


該当する購買受入を設定すると、「買掛請求書検収」という関連リストにデータが登録されてるのが分かります。

f:id:yonet77:20120509214135p:plain


3. 仮受金額の配賦
購買オーダー受入を検収した後の画面です。

f:id:yonet77:20120509214622p:plain


ここで

  1. VAT金額(税額)が計算されている
  2. 仮受金額(ココではマイナス金額)が発生している

といったあたりがポイントになるかなーと思います。

1. VAT金額(税額)が計算されている について

お気づきの方もいらっしゃると思いますが、gOMでは購買オーダーを発行したときには税額計算していません。購買オーダー画面でも税額に相当する項目はありません。
gOMでは、買掛請求書に対して購買受入を紐付ける際に、税額を計算しているようです。

購買オーダーの税額はサプライヤ側で計算するもの、という前提があって、購買オーダー発行時には税額計算しないようにしているかと思います。また、購買オーダー発行時に税額も計算して発注書を送付する、ということは自社の税ルールをサプライヤ側に押し付けることになるので、それはNGなのかな・・?と。
特に、米国のように地域によって税率が変わるような場合だと、自社とサプライヤで税ルールが異なるケースも多々あるから、税額はサプライヤ側で計算すべし、ということなのでしょうかね。

2. 仮受金額(ココではマイナス金額)が発生している について

gOMで登録されている購買受入を紐付けたときに計算された合計金額(画面上でいう「合計配賦金額」)と、買掛請求書に記載されている金額の差分が仮受金額として残ります。
例えば、値引き調整があったとか消費税の計算ルールに差があって微妙な差額が発生したとか・・でしょうかね。
※この仮受金額を残したままにしておくと、「転記」処理(会計インタフェースへの転記)でエラーとなります。

というわけで、この仮受金額に勘定科目を配賦しましょう。
「買掛請求書勘定科目配賦」にて処理します。

f:id:yonet77:20120509233446p:plain


新規買掛請求書勘定科目配賦ボタンから登録画面に移動して、勘定科目/金額を入力して新規登録します。
※予め「勘定科目」マスタを整備しておく必要があります。「総勘定元帳インタフェースメンテナンス」タブよりメンテナンス画面に移動します。

f:id:yonet77:20120509233803p:plain


買掛請求書勘定科目配賦を作成すると、仮受金額がゼロ円になっているのが分かります。

f:id:yonet77:20120509234344p:plain


これにてサプライヤからの買掛請求書がバッチリ消し込まれた状態となりました!
この状態になってから、最後に「転記」を実行すると、会計インタフェースが作成されます。
※会計インタフェースを作成するには、カスタム設定が事前に必要です。また、会計インタフェースが不要であれば、「転記」を実行する必要はないかと思います。
ちなみに、「転記を取消」をすると、「転記」実行前の状態に戻ります。


会計に関する知識も必要となるので、自分にはなかなか厳しいところがあるのですが、使いこなせるようになると良いですねー。
という感じで「買掛請求書」を使ってみた!というお話でした。
ではっ!

Salesforceのタブをアイコン化して画面にまとめて表示してみる

Salesforceをいじってると

あのタブって、どのアプリケーションにあったっけ・・・?

なんてことを時々思うのですが、そんな忘れっぽいのはきっと自分だけでしょうかね。

タブを全部まとめて表示してみたら・・・??

というわけで、なんとなく勢いでこんなページを作ってみました。
   ↓
f:id:yonet77:20120407020445p:plain


アプリケーション毎にタブをアイコン化して画面に並べただけです。。
アイコンがリンクになってるので、アイコンをクリックすれば、そのタブ画面が新たに開きます。

うーん、でも全部のタブはいらないかな?

さらに、あらかじめ表示するグループを定義しておくと、独自のアイコン化メニューも・・
   ↓
f:id:yonet77:20120407020804p:plain



一体、誰得なのか!?と問い詰めるような真似はしないで頂きたいのですが、誰得でしょうかね?実際。。(苦笑)
とまぁ、勢いで作ったので大目に見るとして、こんな感じで作ってみました。

  • 予め設定した情報に基づいてタブをアイコン化して表示する

  • アプリケーション毎にタブをアイコン化して表示する

補足

Web Service APIにてタブの情報は取得できるみたいなので、それに基づいてタブをアイコン化したメニューにしてグルーピングすれば良いんじゃない?という話です。

具体的には、AjaxTookkitを使って、ココの箇所でタブの情報を取得しています。

var tabSets = sforce.connection.describeTabs();

それを一旦、SObject名か、あるいはタブの名称をキーにして配列に格納します。Visualforceページタブの場合を想定して、タブの名称をキーにすることも考えています。
ただ、同一のタブ名称があると・・・・後に読み込んだタブ名が勝ってしまうのでしょうね。そこがネックです。。

あとは、あらかじめ設定しておいた

  1. グループのタイトル
  2. カスタムオブジェクト名 or ラベル名の配列

を読み込んで、タグを生成する・・といった具合です。とてもシンプルですね。。

タグの生成は各自お好きなようにすれば良いかと思います。ココでは単に "fieldset" と "table" を使ってます。

この後は・・・?

特にないです。 (/++)/


・・というと余りにもアレなんでもう少し発展させようと考えると、

  1. コンポーネント化して「ホーム」画面で表示させる
  2. ユーザ毎に自分の好きなように設定できる仕組みを加える
  3. Twitter Bootstrap を取り入れてナイスなUIに仕立ててみる)

といった感じでしょうか。工夫する点としては。。(まー気が向いたら手を加えようかと思う程度です)


Salesforceのタブをアイコン化してみる上で、Ajax Toolkit とjQueryを使ってみた、というお話でした。
あー、今回はサラッと流しました。(笑)
ではッ!

OmniAuth + Salesforce を試してみた (1)

今回はgOMネタから離れて、Railsネタです。(実はRubyをちょこっと使うことがw えぇ、ほんのちょこっとです。)
というわけ(?)で、OmniAuthを使って、SalesforceをOAuthプロバイダにした認証を試してみました。

OmniAuth って?

Railsアプリに対して、Twitter, Facebook... etc によるOAuth認証機能を提供してくれます。詳しい話は、こっちを参照してもらえれば・・思います。

大抵の場合では、Twitter, FacebookをOAuthプロバイダに使ったサンプルが多いです。そのプロバイダとして「Salesforce」も使えるよ、ということで試してみた話となります。
なお、OmniAuthで使えるプロバイダのリストはこんな感じになっています。

そして、Salesforceもありますねー!スバラシイですね〜。

また、Force.comにおけるOAuth2.0の認証については、Digging Deeper into OAuth 2.0 on Force.comに記載していますので、併せてご参照下さい。


それじゃまぁ、やってみましょうか。ちなみに、自分の環境はこんな感じです。

※新しいのを入れろよ、自分... てへぺろ


Salesforce側の設定

Salesforceにログインして、

設定 → アプリケーションの設定 → 開発 → リモートアクセス

で、アプリケーションを登録しておきます。(以下、サンプルです)
なお、取引先責任者メールには連絡先を登録しておけば良いのでは・・?と思います。テキトーですみません。。
f:id:yonet77:20120402223514p:plain


登録した後、コンシューマ鍵コンシューマの秘密を確認しておきましょう。
※後で使います。
f:id:yonet77:20120402223854p:plain

ちなみに、

  • Consumer Key → コンシューマ鍵
  • Consumer Secret → コンシューマの秘密

と訳しているのかと思いますが、「コンシューマの秘密」って何か不思議ww


Railsアプリの作成

※ちなみに、Salesforceのアカウントは持ってるものとして話を始めますので、持ってない場合は先にコチラ(Developerforce)にて開発者用アカウントを用意しておいて下さい。。
Railsアプリをまずは作成しましょうか。

rails new salesforce -d postgresql

Gemfileに以下を追加しておきましょう。

gem 'omniauth'
gem 'omniauth-salesforce'
gem 'pg'

※DatabaseにpostgreSQLを指定しているので、 gem 'pg' も追加しています。
omniauthに該当するのは、上2行分だけです。
そして、gemをインストールしておきましょう。

$ bundle install

Databaseがなければ作成しておきましょう。
※database.yml は適宜修正しておいて下さい。

$ rake db:create

プロバイダ情報の設定

config/initializers/omniauth.rb を新規に作成して、以下を追記しておきましょう。

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :salesforce, ENV['SALESFORCE_KEY'], ENV['SALESFORCE_SECRET']
end

環境変数に格納している値は、とりあえずapplication.rbに追記しておきましょう。

#config/application.rb
module Salesforce
  class Application < Rails::Application
    ....
  end
end

ENV['SALESFORCE_KEY'] = (コンシューマ鍵)
ENV['SALESFORCE_SECRET'] = (コンシューマの秘密)


Sandbox環境や、Database.comにアクセスする場合は、以下のプロバイダ情報も設定しておきましょう。

Rails.application.config.middleware.use OmniAuth::Builder do
  provider OmniAuth::Strategies::SalesforceSandbox,
                       ENV['SALESFORCE_SANDBOX_KEY'],
                       ENV['SALESFORCE_SANDBOX_SECRET']
  provider OmniAuth::Strategies::DatabaseDotCom,
                       ENV['DATABASE_DOT_COM_KEY'],
                       ENV['DATABASE_DOT_COM_SECRET']
end

Model の生成 (User)

Userモデルを作成しておきましょう。

$ rails g model user

そして、作成したマイグレーションファイルを修正しましょう。

# db/migrate/XXXXXXXXXXXXXX_create_users.rb
class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table :users do |t|
      t.string :provider, :null => false
      t.string :uid, :null => false
      t.string :name, :null => false
      t.string :nickname, :null => false

      t.timestamps
    end
    add_index :users, [:provider, :uid]
  end

  def self.down
    drop_table :users
  end
end

そいでもって、Userモデルも修正します。

# app/models/user.rb
class User < ActiveRecord::Base
  def self.create_with_omniauth(auth)
    create! do |user|
      user.provider = auth["provider"]
      user.uid = auth["uid"]
      user.name = auth["info"]["name"]
      user.nickname = auth["info"]["nickname"]
    end
  end
end

※コールバックで取得したデータからUserデータを作成する処理を追加している・・といった感じでしょうか。

そして、migrate コマンドを実行してUserテーブルを作成しておきましょう。

$ rake db:migrate

Controller の生成 (Sessions) & ルーティングの設定

SessionsController を作成しましょう。

$ rails g controller sessions

そして、SessionsControllerに以下の処理を追記します。

# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  def callback
    auth = request.env["omniauth.auth"]
    user = User.find_by_provider_and_uid(auth["provider"], auth["uid"]) || User.create_with_omniauth(auth)
    session[:user_id] = user.id
    redirect_to root_path, :notice => 'Welcome to Salesforce!!'
  end

  def destroy
    session[:user_id] = nil
    redirect_to root_path
  end
end

※providerとuidで該当するUserデータがなければ、Userモデルに追加した User#create_with_omniauth を呼び出して新規作成してます。

ApplicationController には以下を追記しておきます。

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  ...

  helper_method :current_user

  private

  def current_user
    @current_user ||= User.find(session[:user_id]) if session[:user_id]
  end
end

そして、routes.rb に認証のためのルーティングを追記しておきます。

# config/routes.rb
match '/auth/:provider/callback' => 'sessions#callback'
match '/signout' => 'sessions#destroy', :as => :signout

View の生成 (テスト用のページ)

検証用のテストページを生成しましょう。

$ rails g controller test index

とりあえず、index.html.erb はこんな程度で・・

# app/views/test/index.html.erb
<h1>Test#Index</h1>
<% if current_user %>
  Welcome <%= current_user.name %>!
  <%= link_to "Sign Out", signout_path %>
<% else %>
  <%= link_to "Sign in with Salesforce", "/auth/salesforce" %>
<% end %>
<br/>
<p id="notice"><%= notice %></p>

そして、検証用のページのルーティングを追記しておきましょう。

# config/routes.rb
root :to => 'test#index'

あと、public/index.html があれば削除するか、リネームしておきましょう。


検証

サーバを起動しましょう。

$ rails s

http://localhost:3000/ にアクセスして、リンク 'Sign in with Salesforce' をクリックしてみましょう。
f:id:yonet77:20120402234620p:plain

認証後、Salesforce側に画面が遷移します。ここで(素直に)「許可」をクリックして下さい。
f:id:yonet77:20120403000631p:plain

そうすると、localhost側に戻ってきます。
f:id:yonet77:20120403000752p:plain



とまぁ、こんな感じでSalesforceをOAuthプロバイダに使った認証機能を作ることができます。いやー、ホント、こういうgemを作ってくれる開発者ってすごいですよね〜。多々感謝です。
ソースコードココ(Github)に置いておきます。何かの足しになれば...

ちなみに、Salesforceを使って認証させて何か嬉しいのか?と問われると・・回答に詰まってしまうので、そのうち勉強しておきます。。
まぁ、Ap○xとVisual何とか Pageとか、あまり好きじゃないんだよね・・という場合に、RailsからSalesforceにアクセスできるようになりまっせ、といったあたりはあるでしょうか。。


というわけで、この続きはどこかでできたらいーなーと思いつつ・・。
OmniAuthを使ってみた、というお話でした。ではでは〜!

Glovia Order Management (on Salesforce) を使ってみようか (8)

今回も前回(?)に引き続き、商品マスタのネタにしてみます。取り扱うのは、「ロット管理」「シリアル管理」です。

商品のロット管理/シリアル管理って?

ざっと簡単に。。

  • ロット
    • 仕入/製造の単位で採番される固有の番号
    • 詳細はコチラ
  • シリアル
    • 製品に対して採番される固有の番号
    • 詳細はコチラ

いづれにしても、製品がいつ、どうやって製造されたのか追跡可能となるようにして、製品の不具合発生時に迅速に対応できるようにする・・といった具合に使われたりしてる・・・模様です。


gOMではどうやって管理すんの??

gOMでも商品のロット管理機能/シリアル管理機能も備わっています。商品毎に、ロット管理する/しない、シリアル管理する/しないが設定できるようになっています。ただ、ロット管理とシリアル管理の両方は設定できないようになってますが。
まぁ、そんなわけでちょいと見てみましょうか。

ロット管理のOn/Off

gOMの商品マスタに「ロット管理」という項目があります。ロット管理対象の商品に対して、「ロット管理」にチェックを入れておけばOKです。
f:id:yonet77:20120321003110p:plain

シリアル管理のOn/Off

同じくgOMの商品マスタに「シリアル管理」という項目があります。シリアル管理対象の商品に対して、「シリアル管理」にチェックを入れておけばOKです。
f:id:yonet77:20120321003128p:plain

なお、他に「商品当たりのシリアル番号数」という項目があります。これは商品あたりのシリアル番号数を管理するための項目で、商品に複数のシリアル番号が存在する場合に、その個数を指定するみたいです。
デフォルトは「1」ですが、「2」とか指定することもできます。この場合、1つの商品に対して、2つのシリアル番号を割当てることができるみたいです。


さて、ロット番号/シリアル番号がどう生成されて、どう使われるのか?って話ですが、大まかに言えば、入庫のタイミングで採番されて、出庫のタイミングで引当される・・かと思います。そんな流れで見てみましょう。

ロット番号、シリアル番号の入力

gOMでは、以下の処理にて商品が入庫されます。

  1. 購買オーダーの受入
  2. 作業オーダーの完了
  3. 返品の仕分け
  4. 在庫調整
  5. 供給オーダーの受入


※ロット番号/シリアル番号入力のインターフェースは、ほぼ共通しているので、購買オーダーの受入をサンプルにします。。
1. 購買オーダーの受入
購買オーダー受入ライン画面にて、「商品シリアル番号」「商品ロット番号」というボタンがあります。購買オーダーを受け入れした後に、このボタンからシリアル番号/ロット番号を設定する、という感じです。
<購買オーダー受入ライン画面>
f:id:yonet77:20120326231443p:plain




<ロット番号入力画面>
f:id:yonet77:20120326232007p:plain

  • ロット番号入力ボタンをクリックすると、ロット番号入力行が追加されます。
  • ロット入力行の「虫メガネ」アイコンで、登録済のロット番号を検索して、ロット番号入力欄にセットできます。

<シリアル番号入力画面>
f:id:yonet77:20120326232654p:plain

  • シリアル番号入力ボタンをクリックすると、シリアル番号入力行が追加されます。上記の例では、商品を5個受け入れているので、シリアル番号入力行は5行分追加されています。
  • シリアル入力行の「虫メガネ」アイコンで、登録済のシリアル番号を検索して、シリアル番号入力欄にセットできます。

ロット番号、シリアル番号の引当

gOMでは、以下の処理にて商品が出庫されます。

  1. 販売オーダーからの出荷
  2. 作業オーダーの材料出庫

※すみません。ココでも販売オーダーからの出荷だけをサンプルにします。。
1. 販売オーダーからの出荷
販売オーダーライン作成とともに、在庫予約データが作成されます。この在庫予約データに対して、シリアル番号/ロット番号を割当てることができます。
※在庫予約した段階ではなく、梱包指示の段階で割当てることもできますが、ココでは在庫予約した際に割当てる想定にしています。
在庫予約データの画面には「商品シリアル番号」「商品ロット番号」といった見覚えのあるボタンがあります。ここからシリアル番号、ロット番号を割り当てします。
<在庫予約画面>
f:id:yonet77:20120326235244p:plain



<商品ロット番号入力画面>
f:id:yonet77:20120326235508p:plain

  • ロット番号入力ボタンをクリックすると、ロット番号入力行が追加されます。
  • ロット入力行の「虫メガネ」アイコンで、登録済のロット番号を検索して、ロット番号入力欄にセットできます。この段階では、登録済みのロット番号を割り当てる・・のが通常のケースかと思いますので、虫メガネから登録済のロット番号を入力する感じになるでしょう。

<商品シリアル番号入力画面>
f:id:yonet77:20120326235527p:plain

  • シリアル番号入力ボタンをクリックすると、シリアル番号入力行が追加されます。上記の例では、商品を3個予約しているので、シリアル番号入力行は3行分追加されています。
  • シリアル入力行の「虫メガネ」アイコンで、登録済のシリアル番号を検索して、シリアル番号入力欄にセットできます。こちらも登録済のシリアル番号を割り当てる・・のが通常のケースかと思いますので、虫メガネから登録済のシリアル番号を入力する感じになるでしょう。

登録された商品ロット/商品シリアル情報について

それぞれ、こんな感じに登録されます。
<商品ロット>
f:id:yonet77:20120327000352p:plain

  • 1つのロット番号に対して、ロット詳細が複数紐付くように登録されます。
  • ロット詳細は、ロット番号入力時に作成されます。上記の例だと、「000000」は購買オーダー受入時に入力したロットで、「000001」は在庫予約時に入力したロットとなります。
  • ロット番号入力画面で、番号入力して保存したときの動きはこんな感じです。
    • 指定したロット番号が登録されていれば、登録済のロットに紐付くロット詳細のみを作成します。
    • 指定したロット番号が未登録であれば、ロットとロット詳細の両方を作成します。


<商品シリアル>
f:id:yonet77:20120327000359p:plain

  • シリアル番号に対して、処理した内容を追記していくような形態となります。
  • 「最終処理名」にて、最後に処理した内容が確認できます。
  • 「生産」「購買オーダー」「販売オーダー」「返品」セクションにて、どの業務にてシリアル番号を設定したのか識別できるようになっています。

参考:出荷データ

上記の例で、Quick出荷した場合の出荷画面はこんな感じになります。ご参考までに...
f:id:yonet77:20120327001636p:plain



さいごに気になること など

こんな感じで、ロット管理/シリアル管理を行っていきます。
ちょっと気になるのは、商品ロット単位で、在庫がいくつあるのかが良く分からないところですね。出荷時にロット番号を割り当てるのは良いんですが、そのロット番号で在庫がいくつあるのかどうか良く分かりません。。
例えば、「商品ロット」オブジェクトに入庫数、出庫数(その他予約数等も?)といった項目を追加しておいて、ロット詳細を作成するたびに入庫数/出庫数を加算(削除したときには減算?)するトリガとかつけておけば、ロット番号毎の在庫数も把握できるようになるかと思います。
そこらへんは適宜カスタマイズしておきましょうか。


あと、ロットですが、キーになる情報がロット番号だけじゃなくて、ロット番号+在庫場所等でユニークになるようにしたい・・といったケースでは、gOM標準のロット番号入力は利用できません。。ロット番号だけでユニークとなるようにしてしまうので。
その場合は・・またもやカスタマイズで乗り切っちゃって下さい。。





今回は、gOMでのロット管理/シリアル管理について・・・といったお話でした。若干消化不良気味でした(てへぺろ)ので、実際に色々いじってデータがどう動くのか確かめられるのが一番良いと思います!
次回は何のネタにしようか、もしくは次回も続くのかどうか悩み中です。。では!

Glovia Order Management (on Salesforce) を使ってみようか (7)

期間が空いてしまいました。継続するのは大変ですね。。(苦笑)
今回はgOMで用意している商品マスタにある「販売リードタイム」のあたりにしてみようかと思います。

販売オーダーにある「要求日」「約束日」って?(+「計画日」も?)

gOMでは商品マスタに販売リードタイムを設定できますが、それってどこで使われてるの?って話です。
販売オーダーには「要求日」と「約束日」という項目が表示されています。
 ↓
f:id:yonet77:20120313214045p:plain

そもそも「要求日」「約束日」という項目名自体、何を示しているのか分かり難くないかな?なんて思ったり。(まぁ、自分は良く分からなかったですが。。)
それぞれ何を意味しているかというと、こんな感じかと思います。たぶん

  • 要求日
    • 顧客から「この日に欲しいんだけど・・」と要望のあった日付となります。「顧客希望納期」と言っても良いでしょうか。
  • 約束日
    • 顧客から注文のあった商品のリードタイムを考慮して、現実的に納入可能な日付、でしょうか。要求日と合致すれば良いですが、リードタイムが長い場合には、要求日<約束日となることもあるでしょう。
    • ちなみに、販売オーダーに表示されている約束日は、販売オーダーラインの約束日のうち最も遅い日付を表示しています。


なお、販売オーダーラインには、上記2つの日付の他に、「計画日」という日付もあります。
これは出荷に向けて作業開始する日付を意味してるようです。
販売オーダーライン毎に、「要求日」「約束日」「計画日」を持っています。要求日は、販売オーダーの要求日を引き継いでおり、約束日、計画日は商品マスタと要求日から算出しているようです。
 ↓
f:id:yonet77:20120313214201p:plain


販売リードタイムの設定ってどこでやるの?

gOMで設定する販売リードタイムは、以下の2つがあります。

  1. 商品関連情報での設定
  2. システムポリシーでの設定

では、1つずつ...

商品関連情報での設定

商品関連情報で、以下のセクションで設定します。
※「販売オーダーATP」になります。
f:id:yonet77:20120313214315p:plain

システムポリシーでの設定

システムポリシーで、以下のセクションで設定します。
※「販売リードタイム」「出庫リードタイム」「出荷リードタイム」になります。
f:id:yonet77:20120313214328p:plain


設定したリードタイムは、どんな風に設定されるの?

さて、マスタの設定が完了すれば、準備完了です。というわけで、これがどうやって設定されるのか試してみましょうか。
実際には、販売オーダーラインを作成するときに計算されて、「約束日」「計画日」を自動設定します。
その自動設定ルールは、こんな感じになってるみたいです。

パターン 要求日ー本日 > LT
(顧客要求に間に合う)
要求日ー本日 ≦ LT
(顧客要求に間に合わない)
要求日 要求日 要求日
計画日 約束日ーシステムLT 本日+商品マスタLT
約束日 要求日 本日+商品マスタLT+システムLT


<補足>

  • システムLT
    • システムポリシーにある販売リードタイム、出庫リードタイム、出荷リードタイムの合計値
  • 商品マスタLT
    • 商品関連情報にある販売リードオーダーATP

これを見ると、顧客要求に間に合う場合は、要求日を実際の納期(約束日)にして、それに合わせて計画日を設定する。
要求に間に合わない場合は、本日を起点として、できる限り最短の日付を計画日、約束日に設定する。
といった感じでしょうか。

また、どちらのケースでも、約束日と計画日の差は、システムLTとなっています。
これはモノ(商品)が入手できるまでは、商品に依存するけど、モノが手に入ってからの作業(出庫、梱包、出荷)は、商品によらず一定になる、というgOMの前提があるのかと思います。
ホントのところは知らないけど。。。

あと、システムポリシーの「販売リードタイム」「出庫リードタイム」「出荷リードタイム」は出庫、梱包、出荷処理に関わってくるのでしょうかね?
(そのうち調べられたらいーなー)



では実例も交えてみましょうか。。

システムポリシーのLTは 9日 とします。
f:id:yonet77:20120313221828p:plain

商品① リードタイム:5日
f:id:yonet77:20120313221906p:plain

商品② リードタイム:9日
f:id:yonet77:20120313222013p:plain

といった感じに設定しておきます。
そして、要求日を「3/28」として(本日から15日後)販売オーダーを作って、上記の2つの商品を登録してみますと...

  • 間に合う場合(商品①)

f:id:yonet77:20120313222910p:plain

この商品に関しては、リードタイム全体が 9+5 = 14日で、間に合います。
この場合、

  • 要求日 = 3/28
  • 約束日 = 3/28
  • 計画日 = 3/19(3/28 - 9)

となる、というワケですね。


  • 間に合わない場合(商品②)

f:id:yonet77:20120313222923p:plain

この商品に関しては、リードタイム全体が 9+10 = 19日で、間に合いません。
この場合、

  • 要求日 = 3/28
  • 約束日 = 4/1(3/13 + 19)
  • 計画日 = 3/23(4/1 - 9)

となる、というワケですね。


この後はどうすんの?

顧客からの注文を登録した段階で、マスタから算出した約束日が設定され、それが販売オーダーにも反映されるので、標準的な納期回答が即可能になるかと思います。もちろん、商品毎に精度の高いリードタイムが設定されていれば、精度の高い納期がすぐに回答できるようになるでしょう。

マスタの精度を高めるには、定期的なデータ集計&マスタへのフィードバックが必須です。良い感じにレポートを作っておいて、定期的なデータ集計の手間を極力なくす工夫が必要でしょうね〜。マスタへのフィードバックは・・・まぁ、都度行うということで。。

ただ、マスタを一括で編集して、一括で保存する・・・ってあたりは、Salesforce標準では操作性が悪いので、適宜カスタマイズしたりしながらやりやすい形にもっていくことが大事だと思います。。

あと、レポートに関しては、「Weekly Scheduled Orders By Product Code」というgOM標準のレポートで、商品毎に週単位で作業開始しなきゃいけない分をレポート出力してくれます。
例えば、こんな感じのレポートを作っておいて、社内で共有しておけば、出荷漏れ防止に繋がったりするかと思います。
まー、こうやって色んな切り口でレポートを自由に作れる、ってのがSalesforceの良いところなので、自分好みのレポートを作っておいて活用すると良いかと思います。


今回は、商品マスタの販売リードタイムに関する項目について・・というお話でした。
他の項目はどう使われてたり、どう設定すれば良いか・・?なんて話はそのうち少しずつできればいーなーと思いますが、そのうち運が舞い降りたら。

Glovia Order Management (on Salesforce) を使ってみようか (6)

たまには予告通りに前回紹介できなかったネタなどで。。
相変わらずの小出し感たっぷりですが、ドンマイで。

購買オーダーの作成方法(MTO/PTO計画、発注点計画)

gOMでは、MTO/PTO計画・発注点計画をもとに、購買オーダーを作成する機能があります。
タブでいうと、「MTO/PTOプランニング」と「発注点プランニング」に該当しますが、そのままタブに移動しても何も表示されません。。。

 えっ・・コレ、どうやって使うの・・・??

と言わんばかりでした。。初めて見たときは。

というわけで、どうしたら使えるようになるのか、ちょっとご紹介しようと思います。
(自分だけハマった・・のかもしれませんが。)

ちなみに、MTO, PTOは、

  • MTO:Make To Order(受注生産品)
  • PTO:Purchase To Order(受注購買品)

の略で、それぞれお客さんから注文を受けてから、生産活動なり購買活動を行うことを意味します。

準備

MTO/PTO計画・発注点計画から購買オーダーを作成する機能を利用するには、商品関連情報にある「計画方針」を設定しておく必要があります。

<発注点計画を利用する場合>
f:id:yonet77:20120228005128p:plain

<MTO/PTO計画を利用する場合>
f:id:yonet77:20120228005139p:plain

商品関連情報に「計画方針」という項目があります。ココには

  1. マニュアル入力
  2. MTO/PTO計画
  3. 発注点計画

を選択するようになってるので、適宜該当する計画方針をセットします。
なお、「発注点計画」を選択する場合には、

  1. オーダー発注点数
  2. 最小オーダー数
  3. オーダー丸め数

を指定しておく必要があります。


MTO/PTO計画から購買オーダーを作成する

「MTO/PTOプランニング」というタブから操作します。(以下、サンプルです)
f:id:yonet77:20120301233838p:plain

ココには、以下の条件を満たした商品が表示されます。

  • 商品関連情報の「計画方針」が「MTO/PTO」であること
  • 販売オーダーラインの商品として登録されていること

※「在庫予約済」となっていても、販売オーダーラインに作成されていると表示されます。

右端の「アクション」列を見ると分かりますが、商品によって

  • 購買オーダー生成
  • 作業オーダー生成

とあります。ちょっと左側の列で「内作」列を見ると分かると思いますが、「内作」するものについては、作業オーダー(製造指示ですね)を生成して、そうでないものは購買オーダーを生成して仕入れる、という具合ですね。


発注点計画から購買オーダーを作成する

今度は「発注点プランニング」というタブで操作します。(以下、サンプルです)
f:id:yonet77:20120302000624p:plain

ココには、以下の条件を満たした商品が表示されます。

  • 商品関連情報の「計画方針」が「発注点」であること
  • 商品在庫の「使用可能数」+「オーダー数合計」< 商品関連情報の「オーダー発注点数」であること

となります。
ここで、商品在庫の「オーダー数合計」というのが出てきました。これはオーダーは作成してるけど、まだ受入(入庫)してない数量の合計となります。
具体的には、

  • 供給オーダー数
  • 購買オーダー数
  • 作業オーダー数

の合計です。
オーダー数合計は、これから入庫する見込みのある数・・と考えて問題ないかと思います。

そんなわけで、

「今使える在庫数」と「入庫する見込みのある数量」が「オーダー発注点数」を下回ったら発注しないとやヴァイぜ!
今すぐ購買オーダーを作るんだッ!

という感じかと思います。
「推奨数」列には、発注する推奨数が表示されています。
これは

オーダー発注点数 -(使用可能数 + オーダー数合計) に対して、最小オーダー数、オーダー丸め数を考慮して算出する

ようになってると思うのですが、いまいち計算が合わない。。
最小オーダー数、オーダー丸め数ってホントに使われてるのか・・またはどう使われるのか、良く分からないという状況です。。
どうも「オーダー発注点数 -(使用可能数 + オーダー数合計)」だけで算出してないかなー・・?とちょっと疑問が残ります。そのうち問い詰める問合せしようと思います。。

あと、良く分からないのは・・上の画面で、「オーダー発注点数」「最小オーダー数」「オーダー丸め数」が全てゼロになってます。。
商品関連情報には、こんな感じで指定しているんですが、何で全部ゼロなんでしょうか・・・?
f:id:yonet77:20120302002156p:plain

これもまたナゾです。。
そのうち分かったら追記でもしようかな?といった具合で、おあとは悪いですが、この辺りで。。