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.");
            }
        }
Esempio n. 3
0
        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");
        }