--
-- This file is part of TALER
-- Copyright (C) 2025 Taler Systems SA
--
-- TALER is free software; you can redistribute it and/or modify it under the
-- terms of the GNU General Public License as published by the Free Software
-- Foundation; either version 3, or (at your option) any later version.
--
-- TALER is distributed in the hope that it will be useful, but WITHOUT ANY
-- WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-- A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License along with
-- TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>

-- @file merchant-0028.sql
-- @brief Add tables for notifications, product groups and money pots
-- @author Christian Grothoff

BEGIN;

-- Check patch versioning is in place.
SELECT _v.register_patch('merchant-0028', NULL, NULL);

SET search_path TO merchant;

CREATE TABLE merchant_reports
  (report_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
  ,merchant_serial BIGINT NOT NULL
     REFERENCES merchant_instances (merchant_serial) ON DELETE CASCADE
  ,report_program_section TEXT NOT NULL
  ,report_description TEXT NOT NULL
  ,mime_type TEXT NOT NULL
  ,report_token BYTEA NOT NULL CHECK (LENGTH(report_token)=32)
  ,data_source TEXT NOT NULL
  ,target_address TEXT NOT NULL
  ,frequency INT8 NOT NULL
  ,frequency_shift INT8 NOT NULL
  ,next_transmission INT8 NOT NULL
  ,last_error_code INT4 DEFAULT NULL
  ,last_error_detail TEXT DEFAULT NULL
  );
COMMENT ON TABLE merchant_reports
 IS 'Specifies where we should send periodic reports about instance activities';
COMMENT ON COLUMN merchant_reports.report_serial
 IS 'Unique identifier for the report';
COMMENT ON COLUMN merchant_reports.merchant_serial
 IS 'Which instance the report is about';
COMMENT ON COLUMN merchant_reports.report_program_section
 IS 'Which helper program (configuration section) to use to transmit the report';
COMMENT ON COLUMN merchant_reports.mime_type
 IS 'Mime-type to request from the backend for the transmission';
COMMENT ON COLUMN merchant_reports.report_token
 IS 'Token clients requesting the report must include in the /report request';
COMMENT ON COLUMN merchant_reports.data_source
 IS 'Relative URL of the instance for a GET request to request data to send';
COMMENT ON COLUMN merchant_reports.target_address
 IS 'Address to which the report should be sent';
COMMENT ON COLUMN merchant_reports.frequency
 IS 'Relative time with the desired report frequency';
COMMENT ON COLUMN merchant_reports.frequency_shift
 IS 'Relative time by which to offset the actual transmission from the frequency multiple';
COMMENT ON COLUMN merchant_reports.next_transmission
 IS 'Absolute time at which we should do the next transmission';
COMMENT ON COLUMN merchant_reports.last_error_code
 IS 'ErrorCode of the last attempted transmission, NULL on success';
COMMENT ON COLUMN merchant_reports.last_error_detail
 IS 'Additional human-readable text explaining errors from the last transmission attempt (for diagnostics), NULL on success';


CREATE TABLE merchant_product_groups
  (product_group_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
  ,merchant_serial BIGINT NOT NULL
     REFERENCES merchant_instances (merchant_serial) ON DELETE CASCADE
  ,product_group_name TEXT NOT NULL
  ,product_group_description TEXT NOT NULL
  ,UNIQUE (merchant_serial,product_group_name)
  );
COMMENT ON TABLE merchant_product_groups
 IS 'Specifies a product group';
COMMENT ON COLUMN merchant_product_groups.product_group_serial
 IS 'Unique identifier for the group';
COMMENT ON COLUMN merchant_product_groups.merchant_serial
 IS 'Merchant instance using the group';
COMMENT ON COLUMN merchant_product_groups.product_group_name
 IS 'Name for the group';
COMMENT ON COLUMN merchant_product_groups.product_group_description
 IS 'Human-readable description for the group';


CREATE TABLE merchant_money_pots
  (money_pot_serial BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
  ,merchant_serial BIGINT NOT NULL
     REFERENCES merchant_instances (merchant_serial) ON DELETE CASCADE
  ,money_pot_name TEXT NOT NULL
  ,money_pot_description TEXT NOT NULL
  ,pot_totals taler_amount_currency[] NOT NULL
     DEFAULT ARRAY[]::taler_amount_currency[]
  ,UNIQUE (merchant_serial,money_pot_name)
  );
COMMENT ON TABLE merchant_money_pots
 IS 'Accounting construct for tracking finances by groups such as net income, taxes, tips to be paid to staff, etc.';
COMMENT ON COLUMN merchant_money_pots.money_pot_serial
 IS 'Unique identifier for the money pot';
COMMENT ON COLUMN merchant_money_pots.merchant_serial
 IS 'Merchant instance using the group';
COMMENT ON COLUMN merchant_money_pots.money_pot_name
 IS 'Name for the money pot';
COMMENT ON COLUMN merchant_money_pots.money_pot_description
 IS 'Human-readable description for the money pot';
COMMENT ON COLUMN merchant_money_pots.pot_totals
 IS 'Total amounts in the pot';


ALTER TABLE merchant_inventory
  ADD COLUMN product_group_serial INT8 DEFAULT (NULL)
    REFERENCES merchant_product_groups (product_group_serial)
    ON DELETE SET NULL,
  ADD COLUMN money_pot_serial INT8 DEFAULT (NULL)
    REFERENCES merchant_money_pots (money_pot_serial)
    ON DELETE SET NULL,
  DROP COLUMN price, -- forgotten to drop in v27
  ADD COLUMN price_is_net BOOL DEFAULT (FALSE);

COMMENT ON COLUMN merchant_inventory.product_group_serial
  IS 'Specifies the product group a given product is a member of. If NULL, the product is in the __default__ group';
COMMENT ON COLUMN merchant_inventory.money_pot_serial
  IS 'Specifies that sales amounts of this product (excluding taxes on the product that have their own pot specified) should by default be added to the given money pot. If NULL, the money pot rules of the overall order apply instead.';
COMMENT ON COLUMN merchant_inventory.price_is_net
  IS 'If true, the price given is the net price; if false, it is the gross price.';


CREATE FUNCTION merchant_deposits_insert_statistics_trigger()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
  my_instance INT8;
BEGIN
  SELECT mct.merchant_serial
    INTO my_instance
    FROM merchant_contract_terms mct
    JOIN merchant_deposit_confirmations mdc
      USING (order_serial)
    WHERE mdc.deposit_confirmation_serial = NEW.deposit_confirmation_serial;
  CALL merchant_do_bump_amount_stat
    ('deposits-received'
    ,my_instance
    ,CURRENT_TIMESTAMP(0)::TIMESTAMP
    ,NEW.amount_with_fee);
  CALL merchant_do_bump_amount_stat
    ('deposits-fees-paid'
    ,my_instance
    ,CURRENT_TIMESTAMP(0)::TIMESTAMP
    ,NEW.deposit_fee);
  RETURN NEW;
END $$;


-- Whenever a contract is updated, call our trigger to bump statistics
CREATE TRIGGER merchant_deposits_on_insert_statistic
  AFTER INSERT
     ON merchant_deposits
  FOR EACH ROW EXECUTE FUNCTION merchant_deposits_insert_statistics_trigger();


CREATE FUNCTION merchant_expected_transfers_insert_statistics_trigger()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
  my_instance INT8;
BEGIN
  IF NEW.wire_fee IS NOT NULL
  THEN
    SELECT ma.merchant_serial
      INTO my_instance
      FROM merchant_expected_transfers met
      JOIN merchant_accounts ma
        USING (account_serial)
      WHERE met.expected_credit_serial = NEW.expected_credit_serial;
    CALL merchant_do_bump_amount_stat
      ('wire-fees-paid'
      ,my_instance
      ,CURRENT_TIMESTAMP(0)::TIMESTAMP
      ,NEW.wire_fee);
  END IF;
  RETURN NEW;
END $$;


CREATE FUNCTION merchant_expected_transfers_update_statistics_trigger()
RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
  my_instance INT8;
BEGIN
  IF NEW.wire_fee IS NOT NULL AND OLD.wire_fee IS NULL
  THEN
    SELECT ma.merchant_serial
      INTO my_instance
      FROM merchant_expected_transfers met
      JOIN merchant_accounts ma
        USING (account_serial)
      WHERE met.expected_credit_serial = NEW.expected_credit_serial;
    CALL merchant_do_bump_amount_stat
      ('wire-fees-paid'
      ,my_instance
      ,CURRENT_TIMESTAMP(0)::TIMESTAMP
      ,NEW.wire_fee);
  END IF;
  RETURN NEW;
END $$;


-- Whenever a contract is updated, call our trigger to bump statistics
CREATE TRIGGER merchant_expected_transfers_on_insert_statistic
  AFTER INSERT
     ON merchant_expected_transfers
  FOR EACH ROW EXECUTE FUNCTION merchant_expected_transfers_insert_statistics_trigger();
CREATE TRIGGER merchant_expected_transfers_on_update_statistic
  AFTER INSERT
     ON merchant_expected_transfers
  FOR EACH ROW EXECUTE FUNCTION merchant_expected_transfers_update_statistics_trigger();



-- Enable additional bucket statistics
INSERT INTO merchant_statistic_bucket_meta
  (slug
  ,description
  ,stype
  ,ranges
  ,ages)
VALUES
  ('deposits-received'
  ,'total amount customers deposited to us (including deposit fees)'
  ,'amount'
  ,ARRAY['hour'::statistic_range, 'day', 'week', 'month', 'quarter', 'year']
  ,ARRAY[72, 14, 12, 24, 12, 10]
  ),
  ('deposits-fees-paid'
  ,'total amount in deposit fees paid by us or our customers'
  ,'amount'
  ,ARRAY['hour'::statistic_range, 'day', 'week', 'month', 'quarter', 'year']
  ,ARRAY[72, 14, 12, 24, 12, 10]
  ),
  ('wire-fees-paid'
  ,'amount in wire fees paid by'
  ,'amount'
  ,ARRAY['hour'::statistic_range, 'day', 'week', 'month', 'quarter', 'year']
  ,ARRAY[72, 14, 12, 24, 12, 10]
  ),
  ('orders-paid'
  ,'number of orders paid (but not necessarily settled by the exchange)'
  ,'number'
  ,ARRAY['hour'::statistic_range, 'day', 'week', 'month', 'quarter', 'year']
  ,ARRAY[72, 14, 12, 24, 12, 10]
  );



COMMIT;
