public async void ShouldNotBeAbleToSetPoItemStatusWhenNotSellerAdminOwner() { // Try to set a PO item status by a non-authorised user, it should fail // Prepare a new PO and create it Buyer.Po poAsRequested = await CreateBuyerPoAsync(quoteId : GetRandomInt()); var signature = poAsRequested.GetSignatureBytes(_contracts.Web3); await PrepSendFundsToBuyerWalletForPo(_contracts.Web3, poAsRequested); var txReceipt = await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature); txReceipt.Status.Value.Should().Be(1); // Check PO create events var logPoCreated = txReceipt.DecodeAllEvents <PurchaseOrderCreatedLogEventDTO>().FirstOrDefault(); logPoCreated.Should().NotBeNull(); var poNumberAsBuilt = logPoCreated.Event.Po.PoNumber; // Attempt to mark PO item as accepted using preexisting SellerAdmin contract, but with tx executed by the non-authorised ("secondary") user var wss = new SellerAdminService(_contracts.Web3SecondaryUser, _contracts.Deployment.SellerAdminService.ContractHandler.ContractAddress); Func <Task> act = async() => await wss.SetPoItemAcceptedRequestAndWaitForReceiptAsync( poAsRequested.EShopId, poNumberAsBuilt, 1, "SalesOrder1", "Item1"); act.Should().Throw <SmartContractRevertException>().WithMessage(AUTH_EXCEPTION_ONLY_OWNER); }
private async Task DeployAndConfigureEShopAsync() { try { Log($"Deploying eShop: {ContractNewDeploymentConfig.Eshop.EShopId} {ContractNewDeploymentConfig.Eshop.EShopDescription}..."); //----------------------------------------------------------------------------------- // Contract deployments //----------------------------------------------------------------------------------- #region contract deployments // Deploy Address Registry Log(); var contractName = CONTRACT_NAME_ADDRESS_REGISTRY; Log($"Deploying {contractName}..."); var addressRegDeployment = new AddressRegistryDeployment(); AddressRegistryService = await AddressRegistryService.DeployContractAndGetServiceAsync( _web3, addressRegDeployment).ConfigureAwait(false); var addressRegOwner = await AddressRegistryService.OwnerQueryAsync().ConfigureAwait(false); Log($"{contractName} address is: {AddressRegistryService.ContractHandler.ContractAddress}"); Log($"{contractName} owner is : {addressRegOwner}"); // Deploy Eternal Storage Log(); contractName = CONTRACT_NAME_ETERNAL_STORAGE; Log($"Deploying {contractName}..."); var eternalStorageDeployment = new EternalStorageDeployment(); EternalStorageService = await EternalStorageService.DeployContractAndGetServiceAsync( _web3, eternalStorageDeployment).ConfigureAwait(false); var eternalStorageOwner = await EternalStorageService.OwnerQueryAsync().ConfigureAwait(false); Log($"{contractName} address is: {EternalStorageService.ContractHandler.ContractAddress}"); Log($"{contractName} owner is : {eternalStorageOwner}"); // Deploy Business Partner Storage Log(); contractName = CONTRACT_NAME_BUSINESS_PARTNER_STORAGE; Log($"Deploying {contractName}..."); var bpStorageDeployment = new BusinessPartnerStorageDeployment() { ContractAddressOfRegistry = AddressRegistryService.ContractHandler.ContractAddress }; BusinessPartnerStorageService = await BusinessPartnerStorageService.DeployContractAndGetServiceAsync( _web3, bpStorageDeployment).ConfigureAwait(false); var bpStorageOwner = await BusinessPartnerStorageService.OwnerQueryAsync().ConfigureAwait(false); Log($"{contractName} address is: {BusinessPartnerStorageService.ContractHandler.ContractAddress}"); Log($"{contractName} owner is : {bpStorageOwner}"); // Deploy PO Storage Log(); contractName = CONTRACT_NAME_PO_STORAGE; Log($"Deploying {contractName}..."); var poStorageDeployment = new PoStorageDeployment() { ContractAddressOfRegistry = AddressRegistryService.ContractHandler.ContractAddress }; PoStorageService = await PoStorageService.DeployContractAndGetServiceAsync( _web3, poStorageDeployment).ConfigureAwait(false); var poStorageOwner = await PoStorageService.OwnerQueryAsync().ConfigureAwait(false); Log($"{contractName} address is: {PoStorageService.ContractHandler.ContractAddress}"); Log($"{contractName} owner is : {poStorageOwner}"); // Deploy Wallet Buyer Log(); contractName = CONTRACT_NAME_BUYER_WALLET; Log($"Deploying {contractName}..."); var buyerWalletDeployment = new BuyerWalletDeployment() { ContractAddressOfRegistry = AddressRegistryService.ContractHandler.ContractAddress }; BuyerWalletService = await BuyerWalletService.DeployContractAndGetServiceAsync( _web3, buyerWalletDeployment).ConfigureAwait(false); var buyerWalletOwner = await BuyerWalletService.OwnerQueryAsync().ConfigureAwait(false); Log($"{contractName} address is: {BuyerWalletService.ContractHandler.ContractAddress}"); Log($"{contractName} owner is : {buyerWalletOwner}"); // Deploy Wallet Seller Log(); contractName = CONTRACT_NAME_SELLER_ADMIN; Log($"Deploying {contractName}..."); var sellerAdminDeployment = new SellerAdminDeployment() { ContractAddressOfRegistry = AddressRegistryService.ContractHandler.ContractAddress, SellerIdString = ContractNewDeploymentConfig.Seller.SellerId, }; SellerAdminService = await SellerAdminService.DeployContractAndGetServiceAsync( _web3, sellerAdminDeployment).ConfigureAwait(false); var sellerAdminOwner = await SellerAdminService.OwnerQueryAsync().ConfigureAwait(false); Log($"{contractName} address is: {SellerAdminService.ContractHandler.ContractAddress}"); Log($"{contractName} owner is : {sellerAdminOwner}"); // Deploy Purchasing Log(); contractName = CONTRACT_NAME_PURCHASING; Log($"Deploying {contractName}..."); var purchasingDeployment = new PurchasingDeployment() { ContractAddressOfRegistry = AddressRegistryService.ContractHandler.ContractAddress, EShopIdString = ContractNewDeploymentConfig.Eshop.EShopId }; PurchasingService = await PurchasingService.DeployContractAndGetServiceAsync( _web3, purchasingDeployment).ConfigureAwait(false); var purchasingOwner = await PurchasingService.OwnerQueryAsync().ConfigureAwait(false); Log($"{contractName} address is: {PurchasingService.ContractHandler.ContractAddress}"); Log($"{contractName} owner is : {purchasingOwner}"); // Deploy Funding Log(); contractName = CONTRACT_NAME_FUNDING; Log($"Deploying {contractName}..."); var fundingDeployment = new FundingDeployment() { ContractAddressOfRegistry = AddressRegistryService.ContractHandler.ContractAddress }; FundingService = await FundingService.DeployContractAndGetServiceAsync( _web3, fundingDeployment).ConfigureAwait(false); var fundingOwner = await FundingService.OwnerQueryAsync().ConfigureAwait(false); Log($"{contractName} address is: {FundingService.ContractHandler.ContractAddress}"); Log($"{contractName} owner is : {fundingOwner}"); #endregion //----------------------------------------------------------------------------------- // Configure Address Registry //----------------------------------------------------------------------------------- #region configure address registry Log(); Log($"Configuring Address Registry..."); // Add address entry for eternal storage contractName = CONTRACT_NAME_ETERNAL_STORAGE; Log($"Configuring Address Registry, adding {contractName}..."); var txReceipt = await AddressRegistryService.RegisterAddressStringRequestAndWaitForReceiptAsync( contractName, EternalStorageService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); // Add address entry for BP storage contractName = CONTRACT_NAME_BUSINESS_PARTNER_STORAGE; Log($"Configuring Address Registry, adding {contractName}..."); txReceipt = await AddressRegistryService.RegisterAddressStringRequestAndWaitForReceiptAsync( contractName, BusinessPartnerStorageService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); // Add address entry for PO storage contractName = CONTRACT_NAME_PO_STORAGE; Log($"Configuring Address Registry, adding {contractName}..."); txReceipt = await AddressRegistryService.RegisterAddressStringRequestAndWaitForReceiptAsync( contractName, PoStorageService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); // Add address entry for Purchasing contractName = CONTRACT_NAME_PURCHASING; Log($"Configuring Address Registry, adding {contractName}..."); txReceipt = await AddressRegistryService.RegisterAddressStringRequestAndWaitForReceiptAsync( contractName, PurchasingService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); // Add address entry for Funding contractName = CONTRACT_NAME_FUNDING; Log($"Configuring Address Registry, adding {contractName}..."); txReceipt = await AddressRegistryService.RegisterAddressStringRequestAndWaitForReceiptAsync( contractName, FundingService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); // Authorisations. Nothing needed. #endregion //----------------------------------------------------------------------------------- // Configure Eternal Storage //----------------------------------------------------------------------------------- #region configure eternal storage // Authorisations. Bind all contracts that will use eternal storage Log(); Log($"Authorisations for Eternal Storage..."); contractName = CONTRACT_NAME_BUSINESS_PARTNER_STORAGE; Log($"Configuring Eternal Storage, binding {contractName}..."); txReceipt = await EternalStorageService.BindAddressRequestAndWaitForReceiptAsync( BusinessPartnerStorageService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); contractName = CONTRACT_NAME_PO_STORAGE; Log($"Configuring Eternal Storage, binding {contractName}..."); txReceipt = await EternalStorageService.BindAddressRequestAndWaitForReceiptAsync( PoStorageService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); #endregion //----------------------------------------------------------------------------------- // Configure Business Partner Storage //----------------------------------------------------------------------------------- #region configure business partner storage and store master data Log(); Log($"Configuring BP Storage..."); txReceipt = await BusinessPartnerStorageService.ConfigureRequestAndWaitForReceiptAsync( CONTRACT_NAME_ETERNAL_STORAGE).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); //----------------------------------------------------------------------------------- // Add some Business Partner master data //----------------------------------------------------------------------------------- // Need at least one eShop and one Seller to be a useful deployment Log($"Adding eShop master data..."); txReceipt = await BusinessPartnerStorageService.SetEshopRequestAndWaitForReceiptAsync( new Eshop() { EShopId = ContractNewDeploymentConfig.Eshop.EShopId, EShopDescription = ContractNewDeploymentConfig.Eshop.EShopDescription, PurchasingContractAddress = PurchasingService.ContractHandler.ContractAddress, IsActive = true, CreatedByAddress = string.Empty, // filled by contract QuoteSignerCount = Convert.ToUInt32(ContractNewDeploymentConfig.Eshop.QuoteSigners.Count), QuoteSigners = ContractNewDeploymentConfig.Eshop.QuoteSigners }).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); Log($"Adding Seller master data..."); txReceipt = await BusinessPartnerStorageService.SetSellerRequestAndWaitForReceiptAsync( new Seller() { SellerId = ContractNewDeploymentConfig.Seller.SellerId, SellerDescription = ContractNewDeploymentConfig.Seller.SellerDescription, AdminContractAddress = SellerAdminService.ContractHandler.ContractAddress, IsActive = true, CreatedByAddress = string.Empty // filled by contract }).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); #endregion // Authorisations. // Bind all contracts that will use BP storage here - currently none other than owner //----------------------------------------------------------------------------------- // Configure PO Storage //----------------------------------------------------------------------------------- Log(); Log($"Configuring PO Storage..."); txReceipt = await PoStorageService.ConfigureRequestAndWaitForReceiptAsync( CONTRACT_NAME_ETERNAL_STORAGE).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); // Authorisations. Bind all contracts that will use PO storage // Bind Purchasing to PO Storage Log($"Authorisations for PO Storage..."); contractName = CONTRACT_NAME_PURCHASING; Log($"Configuring PO Storage, binding {contractName}..."); txReceipt = await PoStorageService.BindAddressRequestAndWaitForReceiptAsync( PurchasingService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); //----------------------------------------------------------------------------------- // Configure Seller Admin //----------------------------------------------------------------------------------- Log(); Log($"Configuring Seller Admin..."); txReceipt = await SellerAdminService.ConfigureRequestAndWaitForReceiptAsync( CONTRACT_NAME_BUSINESS_PARTNER_STORAGE).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); //----------------------------------------------------------------------------------- // Configure Buyer Wallet //----------------------------------------------------------------------------------- Log(); Log($"Configuring Buyer Wallet..."); txReceipt = await BuyerWalletService.ConfigureRequestAndWaitForReceiptAsync( CONTRACT_NAME_BUSINESS_PARTNER_STORAGE).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); //----------------------------------------------------------------------------------- // Configure Purchasing //----------------------------------------------------------------------------------- Log(); Log($"Configuring Purchasing..."); txReceipt = await PurchasingService.ConfigureRequestAndWaitForReceiptAsync( CONTRACT_NAME_PO_STORAGE, CONTRACT_NAME_BUSINESS_PARTNER_STORAGE, CONTRACT_NAME_FUNDING) .ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); // Authorisations. Bind all contracts that will use Purchasing Log($"Authorisations for Purchasing..."); // Bind BuyerWallet to Purchasing contractName = CONTRACT_NAME_BUYER_WALLET; Log($"Configuring Purchasing, binding {contractName}..."); txReceipt = await PurchasingService.BindAddressRequestAndWaitForReceiptAsync( BuyerWalletService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); // Bind SellerAdmin to Purchasing contractName = CONTRACT_NAME_SELLER_ADMIN; Log($"Configuring Purchasing, binding {contractName}..."); txReceipt = await PurchasingService.BindAddressRequestAndWaitForReceiptAsync( SellerAdminService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); // Bind Funding to Purchasing contractName = CONTRACT_NAME_FUNDING; Log($"Configuring Purchasing, binding {contractName}..."); txReceipt = await PurchasingService.BindAddressRequestAndWaitForReceiptAsync( FundingService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); //----------------------------------------------------------------------------------- // Configure Funding //----------------------------------------------------------------------------------- Log(); Log($"Configuring Funding..."); txReceipt = await FundingService.ConfigureRequestAndWaitForReceiptAsync( CONTRACT_NAME_PO_STORAGE, CONTRACT_NAME_BUSINESS_PARTNER_STORAGE) .ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); // Authorisations. Bind all contracts that will use Funding Log($"Authorisations for Funding..."); // Bind BuyerWallet to Funding contractName = CONTRACT_NAME_BUYER_WALLET; Log($"Configuring Funding, binding {contractName}..."); txReceipt = await FundingService.BindAddressRequestAndWaitForReceiptAsync( BuyerWalletService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); // Bind Purchasing to Funding contractName = CONTRACT_NAME_PURCHASING; Log($"Configuring Funding, binding {contractName}..."); txReceipt = await FundingService.BindAddressRequestAndWaitForReceiptAsync( PurchasingService.ContractHandler.ContractAddress).ConfigureAwait(false); Log($"Tx status: {txReceipt.Status.Value}"); } catch (Exception ex) { Log($"Exception thrown: {ex.Message}"); } finally { Log($"Deploy and configure complete."); } }
public async void ShouldCompletePoItemAndPaySellerLessFees() { // Prepare a new PO Buyer.Po poAsRequested = await CreateBuyerPoAsync(quoteId : GetRandomInt()); var signature = poAsRequested.GetSignatureBytes(_contracts.Web3); // Test setup - transfer required funds from current Web3 acccount to wallet buyer BuyerWalletService bws = _contracts.Deployment.BuyerWalletService; SellerAdminService sas = _contracts.Deployment.SellerAdminService; StandardTokenService sts = new StandardTokenService(_contracts.Web3, poAsRequested.CurrencyAddress); var totalPoValue = poAsRequested.GetTotalCurrencyValue(); var txTransfer = await sts.TransferRequestAndWaitForReceiptAsync(poAsRequested.BuyerWalletAddress, totalPoValue); txTransfer.Status.Value.Should().Be(1); // Create PO on-chain // NB: this approves token transfer from BUYER WALLET contract (NOT msg.sender == current web3 account) to FUNDING contract var txReceiptCreate = await bws.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature); txReceiptCreate.Status.Value.Should().Be(1); _output.WriteLine($"... PO created ..."); // Get the PO number that was assigned var logPoCreated = txReceiptCreate.DecodeAllEvents <PurchaseOrderCreatedLogEventDTO>().FirstOrDefault(); logPoCreated.Should().NotBeNull(); var poNumberAsBuilt = logPoCreated.Event.Po.PoNumber; // NB: Payment goes to the SellerAdmin address var sellerAdminBalanceBefore = await sts.BalanceOfQueryAsync(_contracts.Deployment.SellerAdminService.ContractHandler.ContractAddress); _output.WriteLine($"SellerAdmin balance before completion: {await sellerAdminBalanceBefore.PrettifyAsync(sts)}"); // Process PO item through to completion (completion step will release funds) // Mark PO item as Accepted var txReceiptAccept = await sas.SetPoItemAcceptedRequestAndWaitForReceiptAsync( poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER, SALES_ORDER_NUMBER, SALES_ORDER_ITEM); txReceiptAccept.Status.Value.Should().Be(1); // Mark PO item as Ready for Goods Issue var txReceiptReadyForGI = await sas.SetPoItemReadyForGoodsIssueRequestAndWaitForReceiptAsync( poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER); txReceiptReadyForGI.Status.Value.Should().Be(1); // Mark PO item as Goods Issued var txReceiptGI = await sas.SetPoItemGoodsIssuedRequestAndWaitForReceiptAsync( poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER); txReceiptGI.Status.Value.Should().Be(1); // Mark PO item as Goods Received by the Buyer (so we don't have to wait 30 days) var txReceiptGR = await bws.SetPoItemGoodsReceivedRequestAndWaitForReceiptAsync( poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER); txReceiptGR.Status.Value.Should().Be(1); // Mark PO item as Complete var txReceiptCompleted = await sas.SetPoItemCompletedRequestAndWaitForReceiptAsync( poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER); txReceiptCompleted.Status.Value.Should().Be(1); var poItemValue = poAsRequested.PoItems[PO_ITEM_INDEX].CurrencyValue; _output.WriteLine($"... PO item completed with value {await poItemValue.PrettifyAsync(sts)} ..."); // Check log exists for Escrow release var logPoItemCompleted = txReceiptCompleted.DecodeAllEvents <PurchaseItemEscrowReleasedLogEventDTO>().FirstOrDefault(); logPoItemCompleted.Should().NotBeNull(); // Balance of PO buyer address after PO item rejection var sellerAdminBalanceAfter = await sts.BalanceOfQueryAsync(_contracts.Deployment.SellerAdminService.ContractHandler.ContractAddress); _output.WriteLine($"SellerAdmin balance after completion: {await sellerAdminBalanceAfter.PrettifyAsync(sts)}"); // Checks must include fees var feeBasisPoints = await _contracts.Deployment.PurchasingService.GetFeeBasisPointsQueryAsync(); var fee = poItemValue * feeBasisPoints / 10000; var diff = sellerAdminBalanceAfter - sellerAdminBalanceBefore; diff.Should().Be(poItemValue - fee, "SellerAdmin contract address should increase by PO item value minus fee"); }