yonet77的な雑記帳

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

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

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

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

今回は・・前回とは違う範囲になりますが、発注/仕入の話でも。。

購買オーダーの作り方

gOM標準では購買オーダーは4通りの作り方が用意されています。

  1. Salesforce標準に沿って新規に作成する
    • 単純に「購買」というタブから新規作成する方法。特に解説も不要なほど単純な方法ですね。
  2. 販売オーダーから作成する
    • 受注した分、仕入れる、という感じでしょうか。やり方は単純といやぁ単純です。
  3. 発注点計画から作成する
  4. MTO/PTO計画から作成する

今回は、「2.」の方法についてご紹介します。「3.」「4.」はそのうち、の予定です。(予定は未定)
販売オーダー/販売オーダーラインを入力した後に、販売オーダー画面にある「購買オーダーを生成」というボタンから購買オーダー生成画面に移動します。(下記の画面 ↓)
f:id:yonet77:20120225024733p:plain

ここで、サプライヤを指定して、「販売オーダーから購買商品リストを生成」ボタンをクリックすると、販売オーダーラインが表示されます。
あとは、単価/非請求理由を適宜修正して、「購買オーダー生成」ボタンで購買オーダーを作成します。
なお、このときに納期を指定しておくと、購買オーダーにセットされます。
また、直送のチェックボックスにチェックを入れておくと、購買オーダーの出荷先を変更することができます。

通常は、購買オーダーの出荷先は「在庫場所」に指定した住所になります。(例えば自社の倉庫とか)
ただ、時には、サプライヤからお客様の方に直接配送してもらう方が良い、というケースもあるかと思います。そんなときにこのチェックボックスを利用します。

ココにチェックを入れておくと、出荷先が販売オーダーの出荷先(つまりお客様の出荷先)となります。サプライヤに、直接お客様に送ってもらうよう指示できる、という感じでしょうか。
ただ、サプライヤから直接お客様に商品が配送されるので、運用上「納品書/受領書」といった書類のやり取りが面倒になるかもしれません。。
そんなときは例えばサプライヤに対して「宛名はお客様、納品元は自社」という納品書を作ってもらって、サプライヤに納品書の代行提出をお願いして「受領書」を持ち帰ってもらう・・なんて運用もアリかと思います。(このあたりはシステムとは関係ない話ですが。。)

ぐたぐた書きましたが、こんな感じで購買オーダー/購買オーダーラインを作成したりします。


購買オーダーの変更とかキャンセルとかは・・・?

購買オーダーを作成するまでは良いですが、その後、お客様からの受注変更により購買オーダーも変更するケースもあるかと思います。
ただ、そのときに、

  1. 購買オーダーラインを変更/削除して、変更に対応するケース
  2. 先に作成した購買オーダーラインの数量をキャンセルしたり、オーダー全体をキャンセルする等して、変更に対応するケース
  3. 追加分の購買オーダーラインを新規に作成して、変更に対応するケース

といった対応が考えられますが、これは購買オーダーの発注状況によって、どれを選択するか決まると思います。
購買オーダー自体は作成したけど、サプライヤにまだ発注してない(=未発注)のであれば、「1.」の対応でも良いですが、サプライヤに発注した後(=発注済)だった場合、「2.」や「3.」の対応が必要になると思います。
※詳しいところまでは分からないですが、発注後の変更は変更内容を保存してサプライヤ側に通知する・・というあたりの話が「下請法」にもあったかと思います。。たぶん。
ただ、サプライヤとの関係によっては「3.」の対応ではなく、購買オーダーラインの数量を増加することで対応しても良いのかもしれません。

ちなみに、gOMでは「未発注」or「発注済」というステータスを明示的に持ってない(オーダー日が入ってたら「発注済」と判断しているのかもしれませんが。。)ので、ユーザは処理する購買オーダーの状況を判断して、どちらを選択しなければならないのか、都度考える必要があります。
このあたりは、もう少しシステムがサポートするようにしても良いんじゃないかなー・・と思いますね。
個人的な印象では、gOMは割と「そこらへんの判断も含めて勝手にやってね♪」というスタンスを取っていると感じてて、ちょっとイマイチに思えます。。

閑話休題。
で、話を戻すと「1.」の場合はフツーに購買オーダーラインを変更したり、削除したり・・と対応すれば良いので、特にコメント不要でしょう。
「2.」の場合はどうするのか?というあたりで、少しハマったところ含めて紹介したいと思います。

購買オーダーラインには「キャンセル」情報を管理する項目が用意されています。
 ↓
f:id:yonet77:20120225223201p:plain

この画面上で、

  1. 一部キャンセルする場合(数量減少など)
    • 「キャンセル理由」に該当する理由を選択し、「キャンセル数」に減らす数量を入力して保存する
  2. 全数キャンセルする場合
    • 「キャンセル理由」に該当する理由を選択し、保存する

といった感じになります。
特に、「2.」の場合には、キャンセル数は変更しないでそのまま保存する、というあたりがポイントになります。僕はハマりました。てへぺろ
(なんでこうしたんでしょうね?)


購買オーダーを受け入れよう!

サプライヤに発注した後、サプライヤから(品質にも問題がなく)無事にモノが届いた場合には「受入」処理を実施します。
購買オーダーを受け入れすることで、在庫数が加算されます。

購買オーダー画面にある購買オーダーラインの関連リスト上にある「受入」ボタンから実行するだけですので、処理自体は単純ですね。
「受入」すると、購買オーダー受入と購買オーダー受入ラインが作成されます。これは単に受入した記録を残すためのデータです。。
購買オーダー受入ラインに対して、必要に応じて商品のロット番号やシリアル番号を割当てたりもします。

※ちなみに、購買オーダ受入を「受入取消」することもカンタンにできます。そして、取消すると、レコードが削除されます。
レコードを削除するのはホントにいいのかな・・?と思わずにはいられませんが、まぁ、そういうポリシーなのでしょう、gOMは。

購買オーダーの「受入」に関しては以上です。
が、運用上、こんなケースも発生し得ます、というお話で。。

「受注残」になって購買オーダーを発行/受入した、その後に・・・

気になったのはこんなケースです。以下、「1.」から順番に処理されていったケースです。。

  1. お客様(A)から受注が入って、gOMに販売オーダー/販売オーダーラインを登録したけど、ある商品(P)の在庫がなくて、「受注残」となった。
  2. 商品(P)が在庫切れなので、商品(P)のための購買オーダーを発行した。
  3. サプライヤから商品が届いて、受入処理を実行した。それによりお客様(A)からの受注分が入庫された。(でもgOMでは自動で在庫引当しない)
  4. その直後に、別のお客様(B)から商品(P)に対する急ぎの注文が入って、そのままgOMに販売オーダー/販売オーダーラインを登録した。
  5. 「3.」にて商品はいくらかは入庫されているので、お客様(B)からの受注については「在庫予約」できた。
  6. その後に「1.」で入力した担当者に、商品(P)が入庫されたと通知がきて、「受注残消込」しようとするも、「5.」にて先に在庫予約されてしまっているので、全てが「在庫予約済」とならず、また「受注残」となってしまった・・・!

普通に考えると、「1.」で登録した受注に対する発注した分を、別の受注が先に在庫引当してしまう・・というのは運用上はちょっとマズいんじゃないかな??と思ったりします。
gOMでは購買オーダーの受入処理は、単に商品在庫に入庫する、という処理でしかないので、それがどの在庫予約に関連しているから、他の販売オーダーが登録されても在庫引当できないようにロックするとか、関連する在庫予約に対して在庫引当まで自動で行う・・・・等という機能はありません。

シンプルに言えば、gOMでは

  • 購買オーダーの受入は、単に入庫する
  • 販売オーダーを作成した時点で、在庫があれば在庫がある分だけ在庫引当する。なければ受注残として残しておく。

という方針にしていると思います。

もちろん、購買オーダー受入ラインから関連する購買オーダライン/在庫予約データを引っ張りだせるので、購買オーダーを受入したタイミングで、トリガで先に受注残消込してしまう・・という手もありますが、カスタマイズが必要です。

購買オーダーの受入後、在庫引当までしたけど、購買オーダー受入を「受入取消」したら・・・?

販売オーダー作成時に「受注残」として残ってしまったために、購買オーダーを発行/受入、そして在庫引当(この場合、gOMでは「受注残消込」処理に該当します)まで行ったはいいけど、その後に何らかの理由で購買オーダー受入を取り消しするとどうなるのかッ・・・!?
 ↓
このときは、既に在庫予約済となったデータはそのまま流れるようになります。すなわち、出荷処理までもできます。
すなわち、「実際にはモノはないけど、システム上は出荷されたことになる」ので、情物の不一致(!)が発生します。

これはなんとも微妙ですねー。。。
購買オーダーの受入取消する際に、受入取消して良い状態と悪い状態のどちらにあるのか、gOMではユーザに判断してもらう想定だと思いますが、ユーザ側だけでやるには、なかなかしんどくないかな・・?と(余計な心配ながらも)少し心配しています。


以上2点について、気になったケースを紹介しました。
このあたりは、例えばChatterを使って、全社で情報を共有しながら、「この購買オーダーが受入されたから、こっちの販売オーダーを受注残消込しておかなきゃ!」とか、「これ、ホントは受入したけど、品質不良で取消したいから、この在庫予約を解除して良いかな・・?」なんていうやり取りを運用で回しながら、なんとか折り合いつけていく感じになるのかな?と考えています。。
もっとうまいやり方があるよ!とかありましたら、教えて下さい〜。m(_ _)m


今回、取り上げられなかったネタについて次回紹介できたらいーなーと思いつつ、今日はこのヘンで。。

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

"Glovia Order Management (on Salesforce) を使ってみようか" も、ジョジョ徐々にシリーズ化されつつある今日この頃ですが、そんなに期待しないで頂きたいッ!(キリッ?
※あくまで、気になった小ネタを適当に出してるだけです。。


んで、本日のネタはこんなあたりで。 ↓

受注管理の範囲では、在庫引当をどうやってんの?

gOMでの「在庫予約」って...?

「在庫引当」というのは、お店で「売約済」とか札が商品に貼られているシーンを目にした方も多いと思いますが、アレです。お客さんからの注文に対して、出荷するための商品を確保する・・といったあたりでしょうか。
それをgOMではどうやってやっているか??というと「在庫予約」オブジェクトを使って実現しています。(こんな画面のヤツです↓ )
f:id:yonet77:20120221005300p:plain

この「在庫予約」オブジェクト、在庫引当の後に続く業務(出庫/梱包/出荷..)でも関わってくるので、gOMでは結構大事なオブジェクトです。むやみに削除したりすると面倒ですし、むやみに削除できないようロックされています。

在庫予約データはいつ、どんな感じに作成されるのか...?

gOMでは、販売オーダーラインを作成するときに、在庫予約を一緒に作成します。
つまり、お客さんからの注文明細を登録するときに、自動的に在庫を引き当てにいってる、ということです。
現状、在庫引当のタイミングを制御したい場合は..カスタマイズするしかないみたいです。まぁ、自動的に在庫引当しても大半は大丈夫だと思います。
在庫切れになった商品を発注して、受入(「受領」という表現を使う企業もありますね)した後に在庫引当するタイミングで、微妙だと思うこともありますが、それは購買オーダーのときにでも紹介できれば、と思います。。。

在庫予約がどんな感じに作成されるのー?? というのが以下のパターンとなります。

  1. 商品が「非在庫品」の場合
    • パターン「A」
  2. 商品が「在庫品」で、注文数<在庫数の場合
    • パターン「B」
  3. 商品が「在庫品」で、注文数>在庫数>0の場合
    • パターン「C」
  4. 商品が「在庫品」で、注文数>在庫数=0の場合
    • パターン「D」
パターン A B C D
作成データ件数 1 1 2 1
在庫品or非在庫品? 非在庫品 在庫品 在庫品 在庫品 在庫品
予約ステータス 予約済 予約済 予約済 受注残 受注残
予約数 0 (注文数) (在庫数) 0 0
受注残数 0 0 0 (注文数-在庫数) (注文数)
非在庫品数 (注文数) 0 0 0 0
  • 補足
    • 商品が "在庫品" or "非在庫品" の判定は、「商品関連情報」オブジェクトの「非在庫品」項目で判定します。
    • "受注残":在庫引当できなかった、というステータスを意味します。在庫が補充された後に、再度在庫引当する必要があります。


これを見ると

  • 商品が「非在庫品」(≒在庫管理しない)ものでも在庫予約は作成します。
  • gOMでは在庫引当する時点で、在庫として存在している分から確保していく、という方針のようです。
    • 倉庫にある分から、販売オーダーラインを登録した順番でどんどん在庫引当しちゃえー!んで、在庫引当できなかったら受注残として別途作成しちゃえー・・という感じでしょうか。
    • なので、注文に対して不足があると、在庫予約を2件作成しちゃいます。在庫引当後、出庫指示〜梱包指示〜出荷指示は、在庫予約の単位で処理されるので、注文としては明細が1件でも、出荷時には2件の明細に分かれる、というケースも発生します。(2つの出荷明細の数を足し合わせたら、注文数に等しくなりますが)
    • 分割されるのがイヤだ!という場合には、一旦作っちゃった後に、分割された在庫予約を2件とも削除して下さい。そして、在庫が補充されて「注文数<在庫数」となった段階で、在庫引当処理を実行する・・という流れになります。

(赤枠のボタンが該当します↓ )
f:id:yonet77:20120221014114p:plain

なお、補足ですが、「受注残」として残った在庫予約データについては、在庫が補充されたタイミングで、受注残を消し込む業務が必要となります。(でないと、後続業務(出庫/梱包/出荷)が回らなくなります)
受注残を消し込む操作は、以下の赤枠のボタンが該当します。在庫予約のリストから、消し込みたい在庫予約を選択して、「受注残消し込み」を実行する感じとなります。
f:id:yonet77:20120221014618p:plain


在庫引当を自前のApexコードから起動させたい場合って...?

さてさて、色々とカスタマイズしていく中で、在庫を引き当てるとか、「受注残」として残っている在庫予約に対して、消し込みするといった処理を実装することも(もしかしたら)あるやもしれませぬ。
ということで、調べてみると、gOMの中で「inventoryReserve」クラスがglobalとして定義されていて、以下のようなメソッドを用意しているとのことでした。

  • 在庫引当処理を実行する:gii.inventoryReserve.reservation(List SalesOrderLineIds)
    • 販売オーダーラインのIdのリストを引数にして、gii.inventoryReserve.reservation を呼び出します。
    • 例えば、在庫引当のタイミングを制御したい場合に、一旦在庫予約は削除しておいて、好きなときに上記のメソッドを呼び出せば、在庫引当のタイミングを制御できるようになるかと思います。
  • 受注残の消し込み処理を実行する:gii.inventoryReserve.clearBackorder(List InventoryReserveIds)
    • 在庫予約のIdのリストを引数にして、gii.inventoryReserve.clearBackorder を呼び出します。
    • 例えば、在庫が補充されたタイミングで、「受注残」として残っている在庫予約データを自動で消し込みしたい場合に、上記のメソッドは利用できるかもしれません。。

※上記以外にも在庫予約データを処理するためのメソッドが用意されていますが、そのうち...(紹介できるといーなーと思いつつ)
次回は未定です。