syntax = "proto3";
package upl;
// import "prelude.proto";
import "google/protobuf/empty.proto";

// service Reservation {
//   // Set reservation for a Cart/Sku
//   // It can be LOCAL or GLOBAL
//   // and its subject can be a SKU or a DIVIDED_PRODUCT
//   rpc SetReservation(ReservationRequest) returns (ReservationResponse);
//   // Get reservations by Cart(ID)
//   rpc GetReservationsByCart(e) returns (e);
//   // Clear all reservation for a Cart
//   // If we delete a whole cart in quick
//   rpc ClearReservation(r) returns (e);
// }

service Upl {
  // Create new UPL
  // Just from a procurement or inventory service!
  // No public API should be implemented!
  rpc CreateNew(UplNew) returns (UplObj);
  // Create new UPL in bulk
  // Used during closing a procurement process
  rpc CreateNewBulk(stream UplNew) returns (google.protobuf.Empty);
  // Get UPL by ID
  rpc GetById(ByIdRequest) returns (UplObj);
  // Get UPLs by Sku
  rpc GetBySku(BySkuRequest) returns (stream UplObj);
  // Get UPLs by Sku and Location
  rpc GetBySkuAndLocation(BySkuAndLocationRequest) returns (stream UplObj);
  // Get UPLs by Location
  rpc GetByLocation(ByLocationRequest) returns (stream UplObj);

  // Restore archived UPL to a given Stock
  // Should be two reason:
  //   1) Sold UPL is back for any reason
  //   2) Discarded(Missing) product is back
  // rpc RestoreToStock(e) returns (UplObj);

  // Modify best before date
  // This should not use at all
  // As this info should be correctly provided by
  // the procurement process
  // The only possible usage to correct a bestbefore date
  // error during inventory check.
  rpc SetBestBefore(SetBestBeforeRequest) returns (UplObj);
  // Split one UPL from BulkUpl
  rpc Split(SplitRequest) returns (UplObj);
  // Divide divisible Upl or OpenedUpl into a smaller Upl
  rpc Divide(DivideRequest) returns (UplObj);

  // TODO! Implement this
  // Merge an ancestor and a successor UPL into the ancestor
  // rpc Merge(e) returns (UplObj);

  // Set depreciation
  // ID and comment
  rpc SetDepreciation(DepreciationRequest) returns (UplObj);
  // Remove depreciation
  // Remove the depreciated net retail price as well
  rpc RemoveDepreciation(DepreciationRemoveRequest) returns (UplObj);
  // Set depreciation net retail price
  // Only if there is depceriation ID already set
  rpc SetDepreciationPrice(DepreciationPriceRequest) returns (UplObj);

  // Try to remove deprecation price
  // if already depreciated
  rpc RemoveDeprecationPrice(RemoveDeprecationPriceRequest) returns (UplObj);

  // Put UPL to a Cart (Apply lock)
  rpc LockToCart(CartLockRequest) returns (UplObj);

  // Put UPL to a Delivery (Apply lock)
  // rpc LockToDelivery(e) returns (UplObj);

  // Put UPL to an Inventory (Apply lock)
  rpc LockToInventory(InventoryLockRequest) returns (UplObj);
  // Remove UPL from a Cart (Release lock)
  rpc ReleaseLockFromCart(CartUnlockRequest) returns (UplObj);

  // Remove UPL from a Delivery (Release lock)
  // rpc ReleaseLockFromDelivery(e) returns (UplObj);

  // Remove UPL from an Inventory (Release lock)
  rpc ReleaseLockFromInventory(InventoryUnlockRequest) returns (UplObj);
  // Checkout delivery UPLs to a given Stock(ID)
  // Close a cart (transform lock to location)
  rpc CloseCart(CloseCartRequest) returns (google.protobuf.Empty);

  // Close a delivery (transform lock to location)
  // rpc CloseDelivery(e) returns (e);

  // Close an inventory (remove lock, but no location change)
  rpc CloseInventory(CloseInventoryRequest) returns (google.protobuf.Empty);

  // Put UPLs from Delivery to a given Stock (MOVE)
  // rpc CheckoutDelivery(e) returns (e);

  // Remove UPL from a Cart (Release lock)
  // Return a UPL history
  // todo! Implement history!
  // rpc GetHistory(e) returns (stream HistoryItem);
}

// message e {}

// message ReservationRequest {
//   message Local {
//     string cart_id = 1;
//     string stock_id = 2;
//     oneof Subject {
//       uint32 sku = 3;
//       uint32 divided_product = 4;
//     }
//     uint32 reserved_amount = 5;
//   }
//   message Global {
//     string cart_id = 1;
//     oneof Subject {
//       uint32 sku = 2;
//       uint32 divided_product = 3;
//     }
//     uint32 reserved_amount = 4;
//   }
//   oneof reservation {
//     Local local = 1;
//     Global global = 2;
//   }
// }

// message ReservationResponse {
//   message Local {
//     string cart_id = 1;
//     string stock_id = 2;
//     oneof Subject {
//       uint32 sku = 3;
//       uint32 divided_product = 4;
//     }
//     uint32 reserved_amount = 5;
//     uint32 taken_amount = 6;
//   }
//   message Global {
//     string cart_id = 1;
//     oneof Subject {
//       uint32 sku = 2;
//       uint32 divided_product = 3;
//     }
//     uint32 reserved_amount = 4;
//     uint32 taken_amount = 5;
//   }
//   oneof reservation {
//     Local local = 1;
//     Global global = 2;
//   }
// }

// New UPL object
message UplNew {
  // UPL ID
  string upl_id = 1;
  // Related product ID
  uint32 product_id = 2;
  // Related SKU
  uint32 sku = 3;
  // UPL piece; if bulk, than bigger then 1
  uint32 upl_piece = 4;
  // Best before, if there is any
  string best_before = 5;
  // Location will be Stock(ID)
  uint32 stock_id = 6;
  // Related procurement ID
  uint32 procurement_id = 7;
  // Related procurement net price
  uint32 procurement_net_price = 8;
  // 0 if its not divisible, otherwise the contained amount
  uint32 divisible_amount = 9;
  // User who registered the UPL init data
  uint32 created_by = 10;
}

message ByIdRequest { string upl_id = 1; }

message BySkuRequest { uint32 sku = 1; }

// Possible UPL locations
enum LocationKind {
  Stock = 0;
  Cart = 1;
  Delivery = 2;
  Discard = 3;
}

message ByLocationRequest {
  LocationKind location_kind = 1;
  uint32 location_id = 2;
}

message BySkuAndLocationRequest {
  LocationKind location_kind = 1;
  uint32 location_id = 2;
  uint32 sku = 3;
}

message SetBestBeforeRequest {
  string upl = 1;
  // RFC339 or empty string
  string best_before = 2;
  uint32 created_by = 3;
}

message SplitRequest {
  string upl = 1;
  string new_upl = 2;
  uint32 created_by = 3;
}

message DivideRequest {
  string upl = 1;
  string new_upl = 2;
  uint32 requested_amount = 3;
  uint32 created_by = 4;
}

message DepreciationRequest {
  string upl = 1;
  uint32 depreciation_id = 2;
  string depreciation_comment = 3;
  uint32 created_by = 4;
}

// This should be allowed only from the inventory modul
message DepreciationRemoveRequest {
  string upl = 1;
  uint32 created_by = 2;
}

message DepreciationPriceRequest {
  string upl = 1;
  uint32 depreciation_net_price = 2;
  uint32 created_by = 3;
}

message RemoveDeprecationPriceRequest {
  string upl = 1;
  uint32 created_by = 2;
}

message CartLockRequest {
  string upl = 1;
  uint32 cart_id = 2;
  uint32 created_by = 3;
}

message InventoryLockRequest {
  string upl = 1;
  uint32 inventory_id = 2;
  uint32 created_by = 3;
}

message CartUnlockRequest {
  string upl = 1;
  uint32 cart_id = 2;
  uint32 created_by = 3;
}

message InventoryUnlockRequest {
  string upl = 1;
  uint32 inventory_id = 2;
  uint32 created_by = 3;
}

message CloseCartRequest {
  uint32 cart_id = 1;
  uint32 created_by = 2;
}

message CloseInventoryRequest {
  uint32 inventory_id = 1;
  uint32 created_by = 2;
}

message UplObj {
  message KindSku { uint32 sku = 1; }
  message KindBulkSku {
    uint32 sku = 1;
    uint32 upl_pieces = 2;
  }
  message KindOpenedSku {
    uint32 sku = 1;
    uint32 amount = 2;
    repeated string successors = 3;
  }
  message KindDerivedProduct {
    string derived_from = 1;
    uint32 amount = 2;
  }
  message Depreciation {
    uint32 depreciation_id = 1;
    string depreciation_comment = 2;
    uint32 depreciation_net_price = 3;
  }
  // UPL ID
  string id = 1;
  // Related product id
  uint32 product_id = 2;
  // UPL kind
  oneof kind {
    KindSku sku = 3;
    KindBulkSku bulk_sku = 4;
    KindOpenedSku opened_sku = 5;
    KindDerivedProduct derived_product = 6;
  }
  // Represents how many UPL this unit contains
  // Can bigger then 1 if UplKind is Bulk
  // Otherwise always 1
  uint32 upl_piece = 7;
  // If UPL is healty: no depreciation, no best_before issue
  bool is_healty = 8;
  // Best before date (RFC3339) if there is any
  string best_before = 9;
  // Depreciation object
  Depreciation depreciation = 10;
  // Procurement id
  uint32 procurement_id = 11;
  // Procurement net price
  uint32 procurement_net_price = 12;
  // Is it divisible? Only if SKU or Derived Product and is divisible
  bool is_divisible = 13;
  // Divisible amount; if divisible; otherwise 0
  uint32 divisible_amount = 14;
  // Applied lock
  oneof lock {
    uint32 CartLock = 15;
    uint32 DeliveryLock = 16;
    uint32 InventoryLock = 17;
    google.protobuf.Empty None = 18;
  }
  // Current location
  oneof location {
    uint32 Stock = 19;
    uint32 Delivery = 20;
    uint32 Cart = 21;
    uint32 Discard = 22;
  }
  // If upl is archived ? true : false
  bool is_archived = 27;
  // Created by user
  uint32 created_by = 29;
  // Created at RFC3339
  string created_at = 30;
}