Skip to content

Commit

Permalink
feat: improved performance and code readability
Browse files Browse the repository at this point in the history
  • Loading branch information
abdulhakim2902 committed Sep 26, 2022
1 parent e80527e commit 50ccaa1
Show file tree
Hide file tree
Showing 10 changed files with 711 additions and 694 deletions.
152 changes: 152 additions & 0 deletions pallets/orders/src/functions.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use crate::*;

use frame_support::{
pallet_prelude::*,
sp_runtime::traits::{AccountIdConversion, Hash},
PalletId,
};
use sp_std::vec;

pub const PALLET_ID: PalletId = PalletId(*b"orders!!");

impl<T: Config> Pallet<T> {
pub fn staking_account_id(order_id: HashOf<T>) -> AccountIdOf<T> {
PALLET_ID.into_sub_account(order_id)
}

pub fn generate_order_id(customer_id: &T::AccountId, service_id: &T::Hash) -> T::Hash {
let mut customer_id_bytes = customer_id.encode();
let mut service_id_bytes = service_id.encode();
let account_info = frame_system::Pallet::<T>::account(customer_id);
let mut nonce_bytes = account_info.nonce.encode();

customer_id_bytes.append(&mut service_id_bytes);
customer_id_bytes.append(&mut nonce_bytes);

let seed = &customer_id_bytes;
T::Hashing::hash(seed)
}

pub fn update_order_status(order_id: &T::Hash, status: OrderStatus) -> Option<OrderOf<T>> {
Orders::<T>::mutate(order_id, |order| match order {
None => None,
Some(order) => {
order.status = status;
order.updated_at = pallet_timestamp::Pallet::<T>::get();
Some(order.clone())
},
})
}

pub fn insert_order_to_storage(order: &OrderOf<T>) {
Orders::<T>::insert(order.id, order);
LastOrderByCustomer::<T>::insert(&order.customer_id, order.id);
Self::insert_order_id_into_orders_by_seller(order);
Self::insert_order_id_into_pending_orders_by_seller(order);
Self::insert_order_id_into_orders_by_customer(order);
}

pub fn insert_order_id_into_orders_by_seller(order: &OrderOf<T>) {
match OrdersBySeller::<T>::get(&order.seller_id) {
None => {
OrdersBySeller::<T>::insert(&order.seller_id, vec![order.id]);
},
Some(mut orders) => {
orders.push(order.id);
OrdersBySeller::<T>::insert(&order.seller_id, orders);
},
}
}

pub fn insert_order_id_into_orders_by_customer(order: &OrderOf<T>) {
match OrdersByCustomer::<T>::get(&order.customer_id) {
None => {
OrdersByCustomer::<T>::insert(&order.customer_id, vec![order.id]);
},
Some(mut orders) => {
orders.push(order.id);
OrdersByCustomer::<T>::insert(&order.customer_id, orders);
},
}
}

pub fn insert_order_id_into_pending_orders_by_seller(order: &OrderOf<T>) {
match PendingOrdersBySeller::<T>::get(&order.seller_id) {
None => {
PendingOrdersBySeller::<T>::insert(&order.seller_id, vec![order.id]);
},
Some(mut orders) => {
orders.push(order.id);
PendingOrdersBySeller::<T>::insert(&order.seller_id, orders);
},
}
}

pub fn remove_order_id_from_pending_orders_by_seller(
seller_id: &T::AccountId,
order_id: &T::Hash,
) {
let mut orders = PendingOrdersBySeller::<T>::get(seller_id).unwrap_or_default();
orders.retain(|o_id| o_id != order_id);
PendingOrdersBySeller::<T>::insert(seller_id, orders);
}

pub fn remove_order_id_from_orders_by_seller(seller_id: &T::AccountId, order_id: &T::Hash) {
let mut orders = OrdersBySeller::<T>::get(seller_id).unwrap_or_default();
orders.retain(|o_id| o_id != order_id);
OrdersBySeller::<T>::insert(seller_id, orders);
}

pub fn remove_order_id_from_orders_by_customer(customer_id: &T::AccountId, order_id: &T::Hash) {
let mut orders = OrdersByCustomer::<T>::get(customer_id).unwrap_or_default();
orders.retain(|o_id| o_id != order_id);
OrdersByCustomer::<T>::insert(customer_id, orders);
}

pub fn order_can_be_refunded(order: OrderOf<T>) -> bool {
let dna_sample =
T::GeneticTesting::dna_sample_by_tracking_id(&order.dna_sample_tracking_id).unwrap();
if !dna_sample.is_rejected() {
return false
}
true
}

fn is_pending_order_ids_by_seller_exist(account_id: &T::AccountId) -> bool {
match PendingOrdersBySeller::<T>::get(account_id) {
Some(_arr) => !_arr.is_empty(),
None => false,
}
}
}

impl<T: Config> OrderEventEmitter<T> for Pallet<T> {
fn emit_event_order_failed(order_id: &HashOf<T>) {
match Self::order_by_id(order_id) {
None => Self::deposit_event(Event::OrderNotFound),
Some(order) => Self::deposit_event(Event::OrderFailed(order)),
}
}
}

impl<T: Config> OrderStatusUpdater<T> for Pallet<T> {
fn update_status_failed(order_id: &HashOf<T>) {
match Self::order_by_id(order_id) {
None => Self::deposit_event(Event::OrderNotFound),
Some(order) => {
Self::update_order_status(&order.id, OrderStatus::Failed);
},
}
}

fn remove_order_id_from_pending_orders_by_seller(
seller_id: &AccountIdOf<T>,
order_id: &HashOf<T>,
) {
Self::remove_order_id_from_pending_orders_by_seller(seller_id, order_id);
}

fn is_pending_order_by_seller_exist(seller_id: &AccountIdOf<T>) -> bool {
Self::is_pending_order_ids_by_seller_exist(seller_id)
}
}
159 changes: 159 additions & 0 deletions pallets/orders/src/impl_orders.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
use crate::*;

impl<T: Config> OrderInterface<T> for Pallet<T> {
type Order = OrderOf<T>;
type Error = Error<T>;

fn create_order(
customer_id: &T::AccountId,
service_id: &T::Hash,
price_index: u32,
customer_box_public_key: &T::Hash,
order_flow: ServiceFlow,
) -> Result<Self::Order, Self::Error> {
let service =
T::Services::service_by_id(service_id).ok_or(Error::<T>::ServiceDoesNotExist)?;

let order_id = Self::generate_order_id(customer_id, service_id);
let seller_id = service.get_owner_id();
let prices_by_currency = service.get_prices_by_currency();

if prices_by_currency.is_empty() ||
prices_by_currency.len() - 1 < price_index.try_into().unwrap()
{
return Err(Error::<T>::PriceIndexNotFound)
}

let price_by_currency = &prices_by_currency[price_index as usize];

let currency = &price_by_currency.currency;
let prices = &price_by_currency.price_components;
let additional_prices = &price_by_currency.additional_prices;

let now = pallet_timestamp::Pallet::<T>::get();

// Initialize DnaSample
let dna_sample = T::GeneticTesting::register_dna_sample(seller_id, customer_id, &order_id)
.map_err(|_| Error::<T>::DnaSampleInitalizationError)?;

let order = Order::new(
order_id,
*service_id,
customer_id.clone(),
*customer_box_public_key,
seller_id.clone(),
dna_sample.get_tracking_id().clone(),
currency.clone(),
order_flow,
prices.clone(),
additional_prices.clone(),
now,
now,
);

Self::insert_order_to_storage(&order);

Ok(order)
}

fn cancel_order(
customer_id: &T::AccountId,
order_id: &T::Hash,
) -> Result<Self::Order, Self::Error> {
let order = Orders::<T>::get(order_id).ok_or(Error::<T>::OrderNotFound)?;

if order.get_customer_id() != customer_id {
return Err(Error::<T>::UnauthorizedOrderCancellation)
}

let dna_sample_result =
T::GeneticTesting::dna_sample_by_tracking_id(&order.dna_sample_tracking_id);

if let Some(dna_sample) = dna_sample_result {
if !dna_sample.is_registered() {
return Err(Error::<T>::OngoingOrderCannotBeCancelled)
}
}

// Delete dna sample associated with the order
let _ = T::GeneticTesting::delete_dna_sample(&order.dna_sample_tracking_id);

let order = Self::update_order_status(order_id, OrderStatus::Cancelled)
.ok_or(Error::<T>::OrderNotFound)?;

Ok(order)
}

fn set_order_paid(
escrow_account_id: &T::AccountId,
order_id: &T::Hash,
) -> Result<Self::Order, Self::Error> {
let _ = EscrowKey::<T>::get()
.filter(|account_id| account_id == escrow_account_id)
.ok_or(Error::<T>::Unauthorized)?;

let order = Self::update_order_status(order_id, OrderStatus::Paid)
.ok_or(Error::<T>::OrderNotFound)?;

Ok(order)
}

fn fulfill_order(
seller_id: &T::AccountId,
order_id: &T::Hash,
) -> Result<Self::Order, Self::Error> {
let order = Orders::<T>::get(order_id).ok_or(Error::<T>::OrderNotFound)?;

// Only the seller can fulfill the order
if order.get_seller_id() != seller_id {
return Err(Error::<T>::UnauthorizedOrderFulfillment)
}

let dna_sample_result =
T::GeneticTesting::dna_sample_by_tracking_id(&order.dna_sample_tracking_id);

if let Some(dna_sample) = dna_sample_result {
if !dna_sample.process_success() {
return Err(Error::<T>::DnaSampleNotSuccessfullyProcessed)
}
}

let order = Self::update_order_status(order_id, OrderStatus::Fulfilled)
.ok_or(Error::<T>::OrderNotFound)?;

Ok(order)
}

fn set_order_refunded(
escrow_account_id: &T::AccountId,
order_id: &T::Hash,
) -> Result<Self::Order, Self::Error> {
let _ = EscrowKey::<T>::get()
.filter(|account_id| account_id == escrow_account_id)
.ok_or(Error::<T>::Unauthorized)?;

let order = Orders::<T>::get(order_id).ok_or(Error::<T>::OrderNotFound)?;

if !Self::order_can_be_refunded(order) {
return Err(Error::<T>::OrderNotYetExpired)
}

let order = Self::update_order_status(order_id, OrderStatus::Refunded)
.ok_or(Error::<T>::OrderNotFound)?;

Ok(order)
}

fn update_escrow_key(
account_id: &T::AccountId,
escrow_key: &T::AccountId,
) -> Result<(), Self::Error> {
let _ = EscrowKey::<T>::get()
.filter(|e| e == account_id)
.ok_or(Error::<T>::Unauthorized)?;

EscrowKey::<T>::put(escrow_key);

Ok(())
}
}
1 change: 0 additions & 1 deletion pallets/orders/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,4 @@ pub trait OrderInterface<T: frame_system::Config> {
account_id: &T::AccountId,
escrow_key: &T::AccountId,
) -> Result<(), Self::Error>;
fn is_pending_order_ids_by_seller_exist(account_id: &T::AccountId) -> bool;
}
Loading

0 comments on commit 50ccaa1

Please sign in to comment.