Initial commit: Organized PTC project structure with .gitignore and README

This commit is contained in:
2026-03-23 14:44:39 +09:00
commit 35ababe236
21 changed files with 8921 additions and 0 deletions

421
db/schema.sql Normal file
View File

@@ -0,0 +1,421 @@
-- Company execution budget analysis schema
-- Target database: PostgreSQL 14+
create extension if not exists pgcrypto;
create schema if not exists budget_app;
set search_path = budget_app, public;
create table companies (
id uuid primary key default gen_random_uuid(),
code varchar(30) not null unique,
name varchar(200) not null,
business_number varchar(30),
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create table fiscal_years (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
fiscal_year integer not null,
start_date date not null,
end_date date not null,
is_closed boolean not null default false,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_fiscal_year unique (company_id, fiscal_year),
constraint chk_fiscal_year_dates check (start_date <= end_date)
);
create table departments (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
parent_department_id uuid references departments(id),
code varchar(30) not null,
name varchar(100) not null,
manager_name varchar(100),
is_active boolean not null default true,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_department_code unique (company_id, code)
);
create table employees (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
department_id uuid references departments(id),
employee_no varchar(30) not null,
name varchar(100) not null,
title varchar(100),
email varchar(200),
is_active boolean not null default true,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_employee_no unique (company_id, employee_no)
);
create table business_units (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
code varchar(30) not null,
name varchar(100) not null,
is_active boolean not null default true,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_business_unit_code unique (company_id, code)
);
create table vendors (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
code varchar(30) not null,
name varchar(200) not null,
business_number varchar(30),
contact_name varchar(100),
phone varchar(50),
email varchar(200),
is_active boolean not null default true,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_vendor_code unique (company_id, code)
);
create table clients (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
code varchar(30) not null,
name varchar(200) not null,
business_number varchar(30),
contact_name varchar(100),
phone varchar(50),
email varchar(200),
is_active boolean not null default true,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_client_code unique (company_id, code)
);
create table projects (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
business_unit_id uuid references business_units(id),
department_id uuid references departments(id),
client_id uuid references clients(id),
project_code varchar(40) not null,
project_name varchar(200) not null,
project_type varchar(50),
status varchar(30) not null default 'planning',
contract_amount numeric(18, 2) not null default 0,
start_date date,
end_date date,
manager_employee_id uuid references employees(id),
description text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_project_code unique (company_id, project_code),
constraint chk_project_status check (status in ('planning', 'active', 'on_hold', 'closed', 'cancelled'))
);
create table account_categories (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
code varchar(30) not null,
name varchar(100) not null,
category_type varchar(20) not null,
sort_order integer not null default 0,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_account_category_code unique (company_id, code),
constraint chk_account_category_type check (category_type in ('revenue', 'cost', 'expense'))
);
create table accounts (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
category_id uuid not null references account_categories(id),
code varchar(30) not null,
name varchar(100) not null,
account_type varchar(20) not null,
is_active boolean not null default true,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_account_code unique (company_id, code),
constraint chk_account_type check (account_type in ('revenue', 'cost', 'expense'))
);
create table budget_versions (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
fiscal_year_id uuid not null references fiscal_years(id),
version_name varchar(100) not null,
version_no integer not null,
status varchar(20) not null default 'draft',
created_by uuid references employees(id),
approved_by uuid references employees(id),
approved_at timestamptz,
notes text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_budget_version unique (company_id, fiscal_year_id, version_no),
constraint chk_budget_version_status check (status in ('draft', 'submitted', 'approved', 'archived'))
);
create table budget_items (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
budget_version_id uuid not null references budget_versions(id),
project_id uuid references projects(id),
department_id uuid references departments(id),
account_id uuid not null references accounts(id),
month_no integer not null,
planned_amount numeric(18, 2) not null default 0,
memo text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_budget_item unique (budget_version_id, project_id, department_id, account_id, month_no),
constraint chk_budget_month check (month_no between 1 and 12)
);
create table purchase_requests (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
project_id uuid references projects(id),
department_id uuid references departments(id),
vendor_id uuid references vendors(id),
requester_employee_id uuid references employees(id),
request_no varchar(40) not null,
request_date date not null,
status varchar(20) not null default 'requested',
description text,
total_amount numeric(18, 2) not null default 0,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_purchase_request_no unique (company_id, request_no),
constraint chk_purchase_request_status check (status in ('requested', 'approved', 'rejected', 'ordered', 'cancelled'))
);
create table purchase_request_items (
id uuid primary key default gen_random_uuid(),
purchase_request_id uuid not null references purchase_requests(id) on delete cascade,
account_id uuid not null references accounts(id),
item_name varchar(200) not null,
quantity numeric(18, 3) not null default 1,
unit_price numeric(18, 2) not null default 0,
amount numeric(18, 2) not null default 0,
needed_date date,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create table purchase_orders (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
purchase_request_id uuid references purchase_requests(id),
project_id uuid references projects(id),
department_id uuid references departments(id),
vendor_id uuid references vendors(id),
order_no varchar(40) not null,
order_date date not null,
status varchar(20) not null default 'issued',
total_amount numeric(18, 2) not null default 0,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_purchase_order_no unique (company_id, order_no),
constraint chk_purchase_order_status check (status in ('issued', 'partial_received', 'received', 'cancelled'))
);
create table purchase_order_items (
id uuid primary key default gen_random_uuid(),
purchase_order_id uuid not null references purchase_orders(id) on delete cascade,
account_id uuid not null references accounts(id),
item_name varchar(200) not null,
quantity numeric(18, 3) not null default 1,
unit_price numeric(18, 2) not null default 0,
amount numeric(18, 2) not null default 0,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now()
);
create table invoices (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
project_id uuid references projects(id),
department_id uuid references departments(id),
vendor_id uuid references vendors(id),
client_id uuid references clients(id),
invoice_no varchar(40) not null,
invoice_type varchar(20) not null,
issue_date date not null,
due_date date,
supply_amount numeric(18, 2) not null default 0,
tax_amount numeric(18, 2) not null default 0,
total_amount numeric(18, 2) not null default 0,
status varchar(20) not null default 'issued',
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_invoice_no unique (company_id, invoice_no),
constraint chk_invoice_type check (invoice_type in ('sales', 'purchase')),
constraint chk_invoice_status check (status in ('issued', 'paid', 'cancelled'))
);
create table actual_transactions (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
fiscal_year_id uuid references fiscal_years(id),
project_id uuid references projects(id),
department_id uuid references departments(id),
account_id uuid not null references accounts(id),
vendor_id uuid references vendors(id),
client_id uuid references clients(id),
employee_id uuid references employees(id),
source_type varchar(30) not null,
source_id uuid,
transaction_date date not null,
month_no integer not null,
transaction_type varchar(20) not null,
amount numeric(18, 2) not null,
description text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint chk_actual_month check (month_no between 1 and 12),
constraint chk_transaction_type check (transaction_type in ('revenue', 'cost', 'expense')),
constraint chk_source_type check (source_type in ('manual', 'invoice', 'purchase_order', 'erp', 'excel_upload'))
);
create table cashflow_transactions (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
project_id uuid references projects(id),
department_id uuid references departments(id),
transaction_date date not null,
cashflow_type varchar(20) not null,
amount numeric(18, 2) not null,
description text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint chk_cashflow_type check (cashflow_type in ('inflow', 'outflow'))
);
create table file_import_logs (
id uuid primary key default gen_random_uuid(),
company_id uuid not null references companies(id),
import_type varchar(30) not null,
file_name varchar(255) not null,
row_count integer not null default 0,
success_count integer not null default 0,
failure_count integer not null default 0,
imported_by uuid references employees(id),
imported_at timestamptz not null default now(),
notes text,
constraint chk_import_type check (import_type in ('budget', 'actual', 'project', 'vendor', 'client', 'account'))
);
create table staging_ptc_transactions (
id uuid primary key default gen_random_uuid(),
import_batch varchar(50) not null,
source_file_name varchar(255) not null,
source_sheet_name varchar(100) not null default 'Sheet1',
source_row_no integer not null,
transaction_date_raw varchar(50),
transaction_date date,
in_out varchar(20),
account_code_raw varchar(30),
account_name_raw varchar(100),
department_name_raw varchar(100),
vendor_name_raw varchar(200),
project_code_raw varchar(50),
project_type_raw varchar(50),
project_name_raw varchar(200),
description_raw text,
supply_amount_raw varchar(50),
vat_amount_raw varchar(50),
total_amount_raw varchar(50),
remarks_raw text,
supply_amount numeric(18, 2),
vat_amount numeric(18, 2),
total_amount numeric(18, 2),
normalized_transaction_type varchar(20),
load_status varchar(20) not null default 'loaded',
load_error text,
created_at timestamptz not null default now(),
updated_at timestamptz not null default now(),
constraint uq_staging_ptc_row unique (import_batch, source_row_no),
constraint chk_staging_load_status check (load_status in ('loaded', 'mapped', 'error'))
);
create index idx_projects_company_status on projects(company_id, status);
create index idx_projects_department on projects(department_id);
create index idx_budget_items_project on budget_items(project_id, month_no);
create index idx_budget_items_department on budget_items(department_id, month_no);
create index idx_actual_transactions_project on actual_transactions(project_id, transaction_date);
create index idx_actual_transactions_department on actual_transactions(department_id, transaction_date);
create index idx_actual_transactions_account on actual_transactions(account_id, transaction_date);
create index idx_purchase_orders_project on purchase_orders(project_id, order_date);
create index idx_invoices_project on invoices(project_id, issue_date);
create index idx_staging_ptc_batch on staging_ptc_transactions(import_batch, source_row_no);
create index idx_staging_ptc_project on staging_ptc_transactions(project_code_raw);
create index idx_staging_ptc_account on staging_ptc_transactions(account_code_raw);
create index idx_staging_ptc_department on staging_ptc_transactions(department_name_raw);
create or replace view vw_budget_vs_actual_monthly as
select
bv.company_id,
fy.fiscal_year,
bi.project_id,
bi.department_id,
bi.account_id,
bi.month_no,
sum(bi.planned_amount) as budget_amount,
coalesce(sum(at.amount), 0) as actual_amount,
sum(bi.planned_amount) - coalesce(sum(at.amount), 0) as variance_amount,
case
when sum(bi.planned_amount) = 0 then 0
else round((coalesce(sum(at.amount), 0) / sum(bi.planned_amount)) * 100, 2)
end as execution_rate
from budget_items bi
join budget_versions bv on bv.id = bi.budget_version_id
join fiscal_years fy on fy.id = bv.fiscal_year_id
left join actual_transactions at
on at.company_id = bv.company_id
and coalesce(at.project_id, '00000000-0000-0000-0000-000000000000'::uuid) = coalesce(bi.project_id, '00000000-0000-0000-0000-000000000000'::uuid)
and coalesce(at.department_id, '00000000-0000-0000-0000-000000000000'::uuid) = coalesce(bi.department_id, '00000000-0000-0000-0000-000000000000'::uuid)
and at.account_id = bi.account_id
and at.month_no = bi.month_no
group by
bv.company_id,
fy.fiscal_year,
bi.project_id,
bi.department_id,
bi.account_id,
bi.month_no;
create or replace view vw_project_profit_summary as
select
p.id as project_id,
p.project_code,
p.project_name,
p.status,
p.contract_amount,
coalesce(sum(case when a.account_type = 'revenue' then at.amount else 0 end), 0) as revenue_amount,
coalesce(sum(case when a.account_type in ('cost', 'expense') then at.amount else 0 end), 0) as cost_amount,
coalesce(sum(case when a.account_type = 'revenue' then at.amount else 0 end), 0)
- coalesce(sum(case when a.account_type in ('cost', 'expense') then at.amount else 0 end), 0) as profit_amount,
case
when coalesce(sum(case when a.account_type = 'revenue' then at.amount else 0 end), 0) = 0 then 0
else round(
(
(
coalesce(sum(case when a.account_type = 'revenue' then at.amount else 0 end), 0)
- coalesce(sum(case when a.account_type in ('cost', 'expense') then at.amount else 0 end), 0)
)
/ coalesce(sum(case when a.account_type = 'revenue' then at.amount else 0 end), 0)
) * 100,
2
)
end as profit_rate
from projects p
left join actual_transactions at on at.project_id = p.id
left join accounts a on a.id = at.account_id
group by p.id, p.project_code, p.project_name, p.status, p.contract_amount;