Част 3. Създаване на вериги

В тази статия ще ви покажем как дефинирахме схемите на фирмените бизнес субекти и йерархичната структура на идентификаторите на обекти на тези образувания. Това определя взаимодействието на конзолата между потребителя и информационната система.

Типични спецификации

Цялата типична информация за бизнес обектите на системата е твърдо кодианя в нея. Модулното разпределение на ERP е дефинирано от основните обекти на организационната структура, обектите на платежната система PAY и счетоводната система на служителите на ACC.

ERP SPEC — Таблици на организационната структура

-type locationType() :: normal | extra. -record('Loc', { id = kvs:seq([],[]) :: [] | term(), code = [] :: [] | term(), country = [] :: [] | binary(), city = [] :: [] | binary(), address = [] :: [] | binary(), type = [] :: locationType() }). -record('Branch', { id = kvs:seq([],[]) :: [] | term(), loc = [] :: [] | #'Loc'{} }). -record('Inventory', { id = [] :: [] | binary(), name = [] :: [] | binary(), branch = [] :: [] | #'Branch'{}, type = [] :: term() }). -record('Organization', { name = [] :: [] | binary(), url = [] :: [] | string(), location = [] :: [] | #'Loc'{}, type = [] :: term() }). -record('Person', { id = kvs:seq([],[]) :: [] | term(), cn = [] :: [] | binary(), name = [] :: [] | binary(), displayName = [] :: [] | binary(), location = [] :: #'Loc'{}, type = [] :: term() }). -record('Employee', { id = kvs:seq([],[]) :: [] | binary(), person = [] :: [] | #'Person'{}, org = [] :: [] | #'Organization'{}, branch = [] :: [] | #'Branch'{}, type = [] :: term() }).

PAY SPEC — Таблици на системата за управление на плащанията

Парите се записват във формат {N, M}, където N е броят на десетичните знаци и M е всички значими цифри. По този начин числата се кодират по много начини, като един: 1 = {0,1} = {1,10} = {2,100}. Операцията за умножение в такава система изглежда по следния начин mul({A, B}, {C, D}) -> {A + C, B * D}.

-type fraction_length() :: integer(). -type digits() :: integer(). -type money() :: {fraction_length(),digits()}. -record('Payment', { invoice = [] :: [] | term(), volume = [] :: [] | money(), price = {0,1} :: money(), instrument = [] :: term(), type = [] :: paymentType(), from = [] :: term(), to = [] :: term() }).

PLM SPEC — Таблици на системата за управление на жизнения цикъл

-record('Acc', { id = [] :: [] | binary() | list(), rate = {0,0} :: money() }). -record('Product', { code = [] :: [] | term(), id = kvs:seq([],[]) :: [] | binary(), url = [] :: [] | binary() | list(), engineer = [] :: [] | #'Person'{}, director = [] :: [] | #'Person'{}, owner = [] :: [] | #'Person'{}, organization = [] :: [] | #'Organization'{}, type = [] :: productType() }). -record('Investment', { id = [] :: [] | term(), volume = [] :: [] | money(), price = {0,1} :: money(), instrument = [] :: term(), type = [] :: investmentType(), from = [] :: term(), to = [] :: term() }).

Създаване на коренни вериги

ERP BOOT или стартиране на предприятие е процесът на попълване на основните речници и таблици с основна информация. Това е основно отражение на йерархичната, организационната структура на предприятието. От служител на предприятието, работното му място, местния офис, местната му компания и по-нататък, до група международни компании с офиси в различни страни по света и вероятно дори до съюзите на мултинационални корпорации.

ERP BOOT — Организационна структура на предприятието

Разгледайте примера за организационна структура на фирна Quanterall: Quanterall, главен изпълнител на Aeternity, има офиси в София, Варна (централен офис) и Пловдив. Самата компания оперира само в България, така че групата се състои от една компания.

Добавянето на данните за организацията, сега и за напред, става с помоща на обикновени списъчни комбинации:

-module(erp). -compile(export_all). boot() -> GroupOrgs = [ #'Organization'{ name="Quanterall", url="quanterall.com"} ], HeadBranches = [ #'Branch'{ loc = #'Loc'{ city = "Varna", country = "BG" } }, #'Branch'{ loc = #'Loc'{ city = "Sophia", country = "BG" } }, #'Branch'{ loc = #'Loc'{ city = "Plovdiv", country = "BG" } } ], PartnersOrgs = [ #'Organization'{ name="NYNJA"}, #'Organization'{ name="Catalx"}, #'Organization'{ name="FiaTech"}, #'Organization'{ name="3Stars"}, #'Organization'{ name="SwissEMX"}, #'Organization'{ name="HistoricalPark"}, #'Organization'{ name="Intralinks"} ], Structure = [ {"/erp/group", GroupOrgs}, {"/erp/partners", PartnersOrgs}, {"/erp/quanterall", HeadBranches} ], lists:foreach(fun({Feed, Data}) -> case kvs:get(writer, Feed) of {ok,_} -> skip; {error,_} -> lists:map(fun(X) -> kvs:append(X,Feed) end, Data) end end, Structure).

PAY BOOT — Счетоводство 'CashFlow'

Управлението на аутсорсинга на отчети е съвсем просто: 1) приемаме плащания по фактури, периодично издавани от клиенти, редовно веднъж месечно; 2) плащаме заплати веднъж месечно. Следователно свитъците се групират по календар и се изчисляват месечно.

sal_boot() -> lists:map(fun(#'Product'{code=C} = P) -> lists:map(fun(#'Payment'{}=Pay) -> kvs:append(Pay, "/plm/"++C++"/outcome") end, salaries(C)) end, products()). pay_boot() -> lists:map(fun(#'Product'{code=C} = P) -> lists:map(fun(#'Payment'{}=Pay) -> kvs:append(Pay, "/plm/"++C++"/income") end, payments(C)) end, products()).

PLM BOOT — Бюджетиране на проекти

Инициализацията е почасова за всеки служител на проекта. Този списък ще бъде използван в бъдеще за разпространение на опции.

assignees() -> lists:map(fun(#'Product'{code=C} = P) -> case kvs:get(writer,"/plm/"++C++"/staff") of {error,_} -> lists:map(fun(#'Person'{}=Person) -> kvs:append(Person, "/plm/"++C++"/staff") end,staff(C)); {ok,_} -> skip end end, products()).

Лихвени плащания по подсметка по проект:

accounts() -> lists:map(fun(#'Product'{code=C}) -> lists:map(fun(#'Acc'{id=Id, rate=R}=SubAcc) -> Address = lists:concat(["/fin/acc/",C]), kvs:append(SubAcc,Address), Feed = lists:concat(["/fin/tx/",Id]), case kvs:get(writer, Feed) of {error,_} -> lists:map(fun(#'Payment'{ invoice=I,price=P, volume=V}=Pay) -> kvs:append(rate(Pay,SubAcc,C), Feed) end, payments(C)); {ok,_} -> skip end end, acc(C)) end, plm_boot:products()).

Библиотеката KVS е отговорна за съхранението и работата с данните. Може да прочетете повече за КVS/ KVX в изданието:

2019-04-13 Нова вресия на KVS
synrc/kvs

Капсулиране на структурата на предприятието

Целият код, необходим за създаването на емисиите, обикновено се приема като допълнение наречено ERP, към стандартното приложение. За тази организация, ние използваме собствено Github пространство, което може да бъде различно за вашата организация, дори можете да имате различно име на хранилището, но името на приложението Erlang/OTP винаги е ERP:

enterprizing/erp

Хранилището трябва да разполага с реални данни на компания, които автоматизираме, разкривайки организационната структура, първични данни и речници ако тази информатия не представлява фирмена тайна. Във всеки друг случай хранилище може да бъде частно. Самите приложения могат да се справят с произволни ERP структури.

Примери за заявки до хранилище

Elixir имплементация:

defmodule PLM.Mixfile do use Mix.Project def project() do [ app: :plm, version: "0.7.1", elixir: "~> 1.8.1", description: "PLM Product Lifecycle Management", deps: [{:bpe, "~> 4.7.3"}, {:erp, "~> 0.7.6"}] ] end def application(), do: [mod: {PLM.Application, []}, applications: [:rocksdb, :kvs, :bpe, :erp]] end

Съдържание на главната директория на базата данни на предприятието:

> :writer |> :kvs.all |> :lists.sort [ {:writer, '/acc/quanterall/Plovdiv', 3, [], [], []}, {:writer, '/acc/quanterall/Sophia', 9, [], [], []}, {:writer, '/acc/quanterall/Varna', 23, [], [], []}, {:writer, '/bpe/hist/1562855060639704000', 1, [], [], []}, {:writer, '/bpe/proc', 1, [], [], []}, {:writer, '/erp/group', 1, [], [], []}, {:writer, '/erp/partners', 7, [], [], []}, {:writer, '/erp/quanterall', 3, [], [], []}, {:writer, '/fin/acc/CATALX', 4, [], [], []}, {:writer, '/fin/acc/NYNJA', 4, [], [], []}, {:writer, '/fin/tx/CATALX/R&D', 12, [], [], []}, {:writer, '/fin/tx/CATALX/insurance', 12, [], [], []}, {:writer, '/fin/tx/CATALX/options', 12, [], [], []}, {:writer, '/fin/tx/CATALX/reserved', 12, [], [], []}, {:writer, '/fin/tx/NYNJA/R&D', 5, [], [], []}, {:writer, '/fin/tx/NYNJA/insurance', 5, [], [], []}, {:writer, '/fin/tx/NYNJA/options', 5, [], [], []}, {:writer, '/fin/tx/NYNJA/reserved', 5, [], [], []}, {:writer, '/plm/CATALX/income', 12, [], [], []}, {:writer, '/plm/CATALX/investments', 4, [], [], []}, {:writer, '/plm/CATALX/outcome', 12, [], [], []}, {:writer, '/plm/CATALX/staff', 2, [], [], []}, {:writer, '/plm/NYNJA/income', 5, [], [], []}, {:writer, '/plm/NYNJA/investments', 2, [], [], []}, {:writer, '/plm/NYNJA/outcome', 5, [], [], []}, {:writer, '/plm/NYNJA/staff', 4, [], [], []}, {:writer, '/plm/products', 2, [], [], []} ]

Списък на компаниите в групата:

> :kvs.feed '/erp/group' [{:Organization, 'Quanterall', 'quanterall.com', [], []}]

Списък на основните офиси/клонове на компанията:

> :kvs.feed '/erp/quanterall' [ {:Branch, '1562329445378242000', {:Loc, '1562329445378243000', [], 'BG', 'Plovdiv', [], []}}, {:Branch, '1562329445378241000', {:Loc, '1562329445378242000', [], 'BG', 'Sophia', [], []}}, {:Branch, '1562329445378234000', {:Loc, '1562329445378240000', [], 'BG', 'Varna', [], []}} ]

Списък на контрагентите:

> :kvs.feed '/erp/partners' [ {:Organization, 'Catalx Exchange Inc.', 'catalx.io', [], []}, {:Organization, 'HistoricalPark', [], [], []}, {:Organization, 'NYNJA, Inc.', 'nynja.io', [], []}, {:Organization, 'Intralinks', [], [], []}, {:Organization, 'SwissEMX', [], [], []}, {:Organization, 'FiaTech', [], [], []}, {:Organization, '3Stars', [], [], []} ]

Бюджетиране на проекти по различни направления:

> :kvs.feed '/fin/acc/NYNJA' [ {:Acc, 'NYNJA/insurance', {2, 70}}, {:Acc, 'NYNJA/reserved', {2, 10}}, {:Acc, 'NYNJA/options', {2, 10}}, {:Acc, 'NYNJA/R&D', {2, 10}} ]

Възможност за допълнително възнаграждение на програмисти:

> :kvs.feed '/fin/tx/CATALX/options' [ {:Payment, '1562868880497278000', {0, 1}, {2, 150000}, 'USD', :crypto, [], []}, {:Payment, '1562868880496849000', {0, 1}, {2, 100000}, 'USD', :crypto, [], []}, {:Payment, '1562868880496409000', {0, 1}, {2, 120000}, 'USD', :crypto, [], []}, {:Payment, '1562868880495897000', {0, 1}, {2, 150000}, 'USD', :crypto, [], []}, {:Payment, '1562868880495412000', {0, 1}, {2, 100000}, 'USD', :crypto, [], []}, {:Payment, '1562868880494920000', {0, 1}, {2, 100000}, 'USD', :crypto, [], []}, {:Payment, '1562868880494538000', {0, 1}, {2, 100000}, 'USD', :crypto, [], []}, {:Payment, '1562868880494072000', {0, 1}, {2, 50000}, 'USD', :crypto, [], []}, {:Payment, '1562868880493672000', {0, 1}, {2, 70000}, 'USD', :crypto, [], []}, {:Payment, '1562868880493387000', {0, 1}, {2, 150000}, 'USD', :crypto, [], []}, {:Payment, '1562868880492939000', {0, 1}, {2, 120000}, 'USD', :crypto, [], []}, {:Payment, '1562868880492234000', {0, 1}, {2, 120000}, 'USD', :crypto, [], []} ]

Хора, които работят по проект:

> :kvs.feed '/plm/NYNJA/staff' [ {:Person, '1562868880467887000', 'Maxim Sokhatsky', [], [], [], 1, []}, {:Person, '1562868880467886000', 'Yuri Maslovsky', [], [], [], 8, []}, {:Person, '1562868880467885000', 'Nikolay Dimitrov', [], [], [], 4, []}, {:Person, '1562868880467884000', 'Radostin Dimitrov', [], [], [], 4, []}, {:Person, '1562868880467883000', 'Georgi Spasov', [], [], [], 8, []} ]