Ejemplo n.º 1
0
        public async void ShouldCreatePoAndRetrieveItBySellerAndQuote()
        {
            // 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 logPoCreateRequest = txReceipt.DecodeAllEvents <PurchaseOrderCreateRequestLogEventDTO>().FirstOrDefault();

            logPoCreateRequest.Should().NotBeNull();  // <= PO as requested
            var logPoCreated = txReceipt.DecodeAllEvents <PurchaseOrderCreatedLogEventDTO>().FirstOrDefault();

            logPoCreated.Should().NotBeNull();        // <= PO as built
            var poNumberAsBuilt = logPoCreated.Event.Po.PoNumber;

            // Retrieve the as-built PO
            var poAsBuilt = (await _contracts.Deployment.BuyerWalletService.GetPoByEshopIdAndQuoteQueryAsync(
                                 poAsRequested.EShopId, poAsRequested.QuoteId)).Po;

            // Most fields should be the same between poAsRequested and poAsBuilt (contract adds some fields to the poAsBuilt, e.g. it assigns the poNumber)
            CheckCreatedPoFieldsMatch(poAsRequested.ToStoragePo(), poAsBuilt.ToStoragePo(), poNumberAsBuilt);

            // Info
            DisplayPoHeader(_output, poAsBuilt.ToStoragePo());
        }
Ejemplo n.º 2
0
        public static byte[] GetSignatureBytes(this Buyer.Po po, string privateKeyHex)
        {
            privateKeyHex = privateKeyHex.EnsureHexPrefix();
            var signature = GetSignatureHexString(po, privateKeyHex);

            return(signature.HexToByteArray());
        }
        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);
        }
Ejemplo n.º 4
0
        public async void ShouldGetPoBySellerAndQuote()
        {
            // Prepare a new PO and create it
            var quoteId = GetRandomInt();

            Buyer.Po poAsRequested = await CreateBuyerPoAsync(quoteId);

            var signature = poAsRequested.GetSignatureBytes(_contracts.Web3);

            await PrepSendFundsToBuyerWalletForPo(_contracts.Web3, poAsRequested);

            var txReceiptCreate = await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            txReceiptCreate.Status.Value.Should().Be(1);

            // Get the PO number that was assigned
            var logPoCreated = txReceiptCreate.DecodeAllEvents <PurchaseOrderCreatedLogEventDTO>().FirstOrDefault();

            logPoCreated.Should().NotBeNull();
            var poNumberAsBuilt = logPoCreated.Event.Po.PoNumber;

            // Retrieve PO as-built using Seller and Quote, and check
            var poAsBuilt = (await _contracts.Deployment.BuyerWalletService.GetPoByEshopIdAndQuoteQueryAsync(
                                 poAsRequested.EShopId, quoteId)).Po;

            CheckCreatedPoFieldsMatch(poAsRequested.ToStoragePo(), poAsBuilt.ToStoragePo(), poNumberAsBuilt);
        }
Ejemplo n.º 5
0
        [InlineData(255)]  // po item number shouldnt exist on the PO used for test
        public async void ShouldFailToSetStatusOnNonExistentPoItem(byte poItemNumber)
        {
            // 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 txReceiptCreate = await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            txReceiptCreate.Status.Value.Should().Be(1);

            // Get the PO number that was assigned
            var logPoCreated = txReceiptCreate.DecodeAllEvents <PurchaseOrderCreatedLogEventDTO>().FirstOrDefault();

            logPoCreated.Should().NotBeNull();
            var poNumberAsBuilt = logPoCreated.Event.Po.PoNumber;

            // This PO exists, but items specified shouldn't exist
            Func <Task> act = async() => await _contracts.Deployment.SellerAdminService.SetPoItemAcceptedRequestAndWaitForReceiptAsync(
                poAsRequested.EShopId, poNumberAsBuilt, poItemNumber, SALES_ORDER_NUMBER, SALES_ORDER_ITEM);

            act.Should().Throw <SmartContractRevertException>().WithMessage(PO_ITEM_EXCEPTION_NOT_EXIST);
        }
Ejemplo n.º 6
0
        public async void ShouldSetPoItemStatusTo06GoodsReceivedByBuyer()
        {
            // 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 txReceiptCreate = await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            txReceiptCreate.Status.Value.Should().Be(1);

            // Get the PO number that was assigned
            var logPoCreated = txReceiptCreate.DecodeAllEvents <PurchaseOrderCreatedLogEventDTO>().FirstOrDefault();

            logPoCreated.Should().NotBeNull();
            var poNumberAsBuilt = logPoCreated.Event.Po.PoNumber;

            // Mark PO item as Accepted
            var txReceiptAccept = await _contracts.Deployment.SellerAdminService.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 _contracts.Deployment.SellerAdminService.SetPoItemReadyForGoodsIssueRequestAndWaitForReceiptAsync(
                poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER);

            txReceiptReadyForGI.Status.Value.Should().Be(1);

            // Mark PO item as Goods Issued
            var txReceiptGI = await _contracts.Deployment.SellerAdminService.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 _contracts.Deployment.BuyerWalletService.SetPoItemGoodsReceivedRequestAndWaitForReceiptAsync(
                poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER);

            txReceiptGR.Status.Value.Should().Be(1);

            // Check log exists
            var logPoGR = txReceiptGR.DecodeAllEvents <PurchaseItemGoodsReceivedLogEventDTO>().FirstOrDefault();

            logPoGR.Should().NotBeNull();
            logPoGR.Event.PoItem.Status.Should().Be(PoItemStatus.GoodsReceived);

            // Check PO has been updated correctly
            var po = await GetPoFromSellerContractAndDisplayAsync(poAsRequested.EShopId, poNumberAsBuilt);

            po.PoItems[PO_ITEM_INDEX].Status.Should().Be(PoItemStatus.GoodsReceived);
            var block = await _contracts.Web3.Eth.Blocks.GetBlockWithTransactionsByNumber.SendRequestAsync(txReceiptGR.BlockNumber);

            var blockTimestamp = block.Timestamp.Value;

            po.PoItems[PO_ITEM_INDEX].GoodsReceivedDate.Should().Be(blockTimestamp);
        }
Ejemplo n.º 7
0
 public static byte[] GetSignatureBytes(this Buyer.Po po, IWeb3 web3)
 {
     if (!(web3.TransactionManager.Account is Account a))
     {
         throw new NotSupportedException("Account object needed to expose private key");
     }
     return(po.GetSignatureBytes(a.PrivateKey));
 }
Ejemplo n.º 8
0
        public static async Task PrepSendFundsToBuyerWalletForPo(Web3.Web3 fromWeb3, Buyer.Po po)
        {
            // Transfer required funds (tokens) from given Web3 acccount to buyer wallet given on po
            StandardTokenService sts = new StandardTokenService(fromWeb3, po.CurrencyAddress);
            var txTransfer           = await sts.TransferRequestAndWaitForReceiptAsync(po.BuyerWalletAddress, po.GetTotalCurrencyValue());

            txTransfer.Status.Value.Should().Be(1);
        }
Ejemplo n.º 9
0
        public static string GetSignatureHexString(this Buyer.Po po, string privateKeyHex)
        {
            privateKeyHex = privateKeyHex.EnsureHexPrefix();
            var hashEncoded = new ABIEncode().GetSha3ABIEncoded(new ABIValue(new TupleType(), po));
            var signature   = new EthereumMessageSigner().Sign(hashEncoded, privateKeyHex);

            return(signature);
        }
Ejemplo n.º 10
0
        public async void ShouldRejectPoItemAndRefundBuyer()
        {
            // 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
            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 WALLET BUYER contract (NOT msg.sender == current web3 account) to FUNDING contract
            var txReceiptCreate = await _contracts.Deployment.BuyerWalletService.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: Refunds go to the PO buyer wallet address (not the po buyer address from the PO header, which represents the user)
            // Balance of PO buyer address before refund
            var poBuyerWalletAddressBalanceBefore = await sts.BalanceOfQueryAsync(poAsRequested.BuyerWalletAddress);

            _output.WriteLine($"PO buyer wallet address balance before refund: {await poBuyerWalletAddressBalanceBefore.PrettifyAsync(sts)}");

            // Do the refund (achieved by marking the PO item as rejected)
            var txReceiptPoItemReject = await _contracts.Deployment.SellerAdminService.SetPoItemRejectedRequestAndWaitForReceiptAsync(
                poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER);

            txReceiptPoItemReject.Status.Value.Should().Be(1);
            var poItemValue = poAsRequested.PoItems[PO_ITEM_INDEX].CurrencyValue;

            _output.WriteLine($"... PO item rejected with value {await poItemValue.PrettifyAsync(sts)} ...");

            // Check log exists for Escrow refund
            var logPoItemReject = txReceiptPoItemReject.DecodeAllEvents <PurchaseItemEscrowRefundedLogEventDTO>().FirstOrDefault();

            logPoItemReject.Should().NotBeNull();

            // Balance of PO buyer wallet address after PO item rejection
            var poBuyerWalletAddressBalanceAfter = await sts.BalanceOfQueryAsync(poAsRequested.BuyerWalletAddress);

            _output.WriteLine($"PO buyer wallet address balance after refund: {await poBuyerWalletAddressBalanceAfter.PrettifyAsync(sts)}");

            // Checks
            var diff = poBuyerWalletAddressBalanceAfter - poBuyerWalletAddressBalanceBefore;

            diff.Should().Be(poItemValue, "PO buyer wallet should have increased by value of the PO item");
        }
Ejemplo n.º 11
0
        public async void ShouldFailToCreatePoWithoutFunding()
        {
            // Prepare a new PO, notice it is created with a large value, in case of leftover tokens transferred from other tests
            Buyer.Po poAsRequested = await CreateBuyerPoAsync(quoteId : GetRandomInt(), isLargeValue : true);

            var signature = poAsRequested.GetSignatureBytes(_contracts.Web3);
            // DONT send any funds, so BuyerWallet has insufficient funds and creation should fail
            Func <Task> act = async() => await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            act.Should().Throw <SmartContractRevertException>(); // exception thrown by token, so can't know what actual message will be
        }
Ejemplo n.º 12
0
        public async void ShouldFailToCreatePoWhenEshopOrSellerIsInactive()
        {
            // Prepare a new PO
            Buyer.Po poAsRequested = await CreateBuyerPoAsync(quoteId : GetRandomInt());

            var signature = poAsRequested.GetSignatureBytes(_contracts.Web3);

            await PrepSendFundsToBuyerWalletForPo(_contracts.Web3, poAsRequested);

            // Temporarily make eShop inactive
            var eShop = (await _contracts.Deployment.BusinessPartnerStorageService.GetEshopQueryAsync(poAsRequested.EShopId)).EShop;

            eShop.Should().NotBeNull();
            eShop.IsActive = false;
            var eShopSetTx = await _contracts.Deployment.BusinessPartnerStorageService.SetEshopRequestAndWaitForReceiptAsync(eShop);

            eShopSetTx.Status.Value.Should().Be(1);

            // Attempt to create PO, it should fail
            Func <Task> act = async() => await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            act.Should().Throw <SmartContractRevertException>().WithMessage(PO_EXCEPTION_ESHOP_INACTIVE);

            // Make eShop active again, else we will mess up other tests
            eShop.IsActive = true;
            eShopSetTx     = await _contracts.Deployment.BusinessPartnerStorageService.SetEshopRequestAndWaitForReceiptAsync(eShop);

            eShopSetTx.Status.Value.Should().Be(1);

            // Temporarily make Seller inactive
            var seller = (await _contracts.Deployment.BusinessPartnerStorageService.GetSellerQueryAsync(poAsRequested.SellerId)).Seller;

            seller.Should().NotBeNull();
            seller.IsActive = false;
            var sellerSetTx = await _contracts.Deployment.BusinessPartnerStorageService.SetSellerRequestAndWaitForReceiptAsync(seller);

            sellerSetTx.Status.Value.Should().Be(1);

            // Attempt to create PO, it should fail
            act = async() => await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            act.Should().Throw <SmartContractRevertException>().WithMessage(PO_EXCEPTION_SELLER_INACTIVE);

            // Make seller active again, else we mess up other tests
            seller.IsActive = true;
            sellerSetTx     = await _contracts.Deployment.BusinessPartnerStorageService.SetSellerRequestAndWaitForReceiptAsync(seller);

            sellerSetTx.Status.Value.Should().Be(1);
        }
Ejemplo n.º 13
0
        public async void ShouldFailToCreatePoWhenEshopDoesNotExist()
        {
            // Prepare a new PO with a non-existent eShop
            Buyer.Po poAsRequested = await CreateBuyerPoAsync(quoteId : GetRandomInt());

            poAsRequested.EShopId = GetRandomString();
            var signature = poAsRequested.GetSignatureBytes(_contracts.Web3);

            await PrepSendFundsToBuyerWalletForPo(_contracts.Web3, poAsRequested);

            // Attempt to create PO, it should fail
            Func <Task> act = async() => await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            act.Should().Throw <SmartContractRevertException>().WithMessage(PO_EXCEPTION_ESHOP_NO_PURCH_ADD);
        }
Ejemplo n.º 14
0
        public async void ShouldFailToCreatePoWhenQuoteHasExpired()
        {
            // Prepare a new PO with quote expiry date to be expired
            Buyer.Po poAsRequested = await CreateBuyerPoAsync(quoteId : GetRandomInt());

            poAsRequested.QuoteExpiryDate = new BigInteger(DateTimeOffset.Now.ToUnixTimeSeconds() - 3600); // quote expired an hour ago
            var signature = poAsRequested.GetSignatureBytes(_contracts.Web3);

            await PrepSendFundsToBuyerWalletForPo(_contracts.Web3, poAsRequested);

            // Attempt to create PO, it should fail
            Func <Task> act = async() => await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            act.Should().Throw <SmartContractRevertException>().WithMessage(QUOTE_EXCEPTION_EXPIRY_PASSED);
        }
Ejemplo n.º 15
0
        public async void ShouldFailToCreatePoWithoutCorrectSigner()
        {
            // Prepare a new PO
            Buyer.Po poAsRequested = await CreateBuyerPoAsync(quoteId : GetRandomInt());

            // DONT use a valid address to sign it, creation should fail. Sign it with the 2ndry user,
            // whereas the eshop is configured to have at least main Web3 user as signer.
            // See BusinessPartnerStorage.sol master data creation in:
            //   Nethereum.eShop\src\contracts\Nethereum.Commerce.Contracts\Deployment\ContractDeployment.cs
            var signature = poAsRequested.GetSignatureBytes(_contracts.Web3SecondaryUser);

            await PrepSendFundsToBuyerWalletForPo(_contracts.Web3, poAsRequested);

            Func <Task> act = async() => await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            act.Should().Throw <SmartContractRevertException>().WithMessage(QUOTE_EXCEPTION_WRONG_SIG);
        }
Ejemplo n.º 16
0
        public async void ShouldFailToSetStatusTo06GoodsReceivedByNonBuyer()
        {
            // 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 txReceiptCreate = await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            txReceiptCreate.Status.Value.Should().Be(1);

            // Get the PO number that was assigned
            var logPoCreated = txReceiptCreate.DecodeAllEvents <PurchaseOrderCreatedLogEventDTO>().FirstOrDefault();

            logPoCreated.Should().NotBeNull();
            var poNumberAsBuilt = logPoCreated.Event.Po.PoNumber;

            // Mark PO item as Accepted
            var txReceiptAccept = await _contracts.Deployment.SellerAdminService.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 _contracts.Deployment.SellerAdminService.SetPoItemReadyForGoodsIssueRequestAndWaitForReceiptAsync(
                poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER);

            txReceiptReadyForGI.Status.Value.Should().Be(1);

            // Mark PO item as Goods Issued
            var txReceiptGI = await _contracts.Deployment.SellerAdminService.SetPoItemGoodsIssuedRequestAndWaitForReceiptAsync(
                poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER);

            txReceiptGI.Status.Value.Should().Be(1);

            // Setting Goods Received by an EoA that is not the buyer/PO owner should fail, only PO owner can do this
            // Use preexisting BuyerWallet contract, but with tx executed by the non-buyer ("secondary") user
            var         wbs = new BuyerWalletService(_contracts.Web3SecondaryUser, _contracts.Deployment.BuyerWalletService.ContractHandler.ContractAddress);
            Func <Task> act = async() => await wbs.SetPoItemGoodsReceivedRequestAndWaitForReceiptAsync(
                poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER);

            act.Should().Throw <SmartContractRevertException>().WithMessage(GOODS_RECEIPT_EXCEPTION_NOT_PO_OWNER);
        }
Ejemplo n.º 17
0
        public async void ShouldFailToSetStatusTo06GoodsReceivedBySeller()
        {
            // 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 txReceiptCreate = await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            txReceiptCreate.Status.Value.Should().Be(1);

            // Get the PO number that was assigned
            var logPoCreated = txReceiptCreate.DecodeAllEvents <PurchaseOrderCreatedLogEventDTO>().FirstOrDefault();

            logPoCreated.Should().NotBeNull();
            var poNumberAsBuilt = logPoCreated.Event.Po.PoNumber;

            // Mark PO item as Accepted
            var txReceiptAccept = await _contracts.Deployment.SellerAdminService.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 _contracts.Deployment.SellerAdminService.SetPoItemReadyForGoodsIssueRequestAndWaitForReceiptAsync(
                poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER);

            txReceiptReadyForGI.Status.Value.Should().Be(1);

            // Mark PO item as Goods Issued
            var txReceiptGI = await _contracts.Deployment.SellerAdminService.SetPoItemGoodsIssuedRequestAndWaitForReceiptAsync(
                poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER);

            txReceiptGI.Status.Value.Should().Be(1);

            // Setting Goods Received by Seller should fail, seller can only set GR after 30 days
            Func <Task> act = async() => await _contracts.Deployment.SellerAdminService.SetPoItemGoodsReceivedRequestAndWaitForReceiptAsync(
                poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER);

            act.Should().Throw <SmartContractRevertException>().WithMessage(GOODS_RECEIPT_EXCEPTION_INSUFFICIENT_DAYS);
        }
Ejemplo n.º 18
0
        public async void ShouldFailToCreatePoWhenQuoteAlreadyUsed()
        {
            // 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 txReceiptCreate = await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            txReceiptCreate.Status.Value.Should().Be(1);

            // Attempt to create PO using the same quote again, it should fail
            await PrepSendFundsToBuyerWalletForPo(_contracts.Web3, poAsRequested);

            Func <Task> act = async() => await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            act.Should().Throw <SmartContractRevertException>().WithMessage(QUOTE_EXCEPTION_QUOTE_IN_USE);
        }
Ejemplo n.º 19
0
        public async void ShouldSetPoItemStatusTo02Accepted()
        {
            // 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 txReceiptCreate = await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            txReceiptCreate.Status.Value.Should().Be(1);

            // Get the PO number that was assigned
            var logPoCreated = txReceiptCreate.DecodeAllEvents <PurchaseOrderCreatedLogEventDTO>().FirstOrDefault();

            logPoCreated.Should().NotBeNull();
            var poNumberAsBuilt = logPoCreated.Event.Po.PoNumber;

            await GetPoFromSellerContractAndDisplayAsync(poAsRequested.EShopId, poNumberAsBuilt);

            // Mark PO item as Accepted
            var txReceiptAccept = await _contracts.Deployment.SellerAdminService.SetPoItemAcceptedRequestAndWaitForReceiptAsync(
                poAsRequested.EShopId, poNumberAsBuilt, PO_ITEM_NUMBER, SALES_ORDER_NUMBER, SALES_ORDER_ITEM);

            txReceiptAccept.Status.Value.Should().Be(1);

            // Check log exists for Accepted
            var logPoAccepted = txReceiptAccept.DecodeAllEvents <PurchaseItemAcceptedLogEventDTO>().FirstOrDefault();

            logPoAccepted.Should().NotBeNull();
            logPoAccepted.Event.PoItem.Status.Should().Be(PoItemStatus.Accepted);

            // Check PO has been updated correctly
            var po = await GetPoFromSellerContractAndDisplayAsync(poAsRequested.EShopId, poNumberAsBuilt);

            po.PoItems[PO_ITEM_INDEX].SoNumber.Should().Be(SALES_ORDER_NUMBER);
            po.PoItems[PO_ITEM_INDEX].SoItemNumber.Should().Be(SALES_ORDER_ITEM);
            po.PoItems[PO_ITEM_INDEX].Status.Should().Be(PoItemStatus.Accepted);
        }
Ejemplo n.º 20
0
        public static BigInteger GetTotalCurrencyValue(this Buyer.Po po)
        {
            if (po == null)
            {
                return(0);
            }
            if (po.PoItems == null)
            {
                return(0);
            }
            if (po.PoItems.Count == 0)
            {
                return(0);
            }

            BigInteger total = 0;

            for (int i = 0; i < po.PoItems.Count; i++)
            {
                total += po.PoItems[i].CurrencyValue;
            }
            return(total);
        }
Ejemplo n.º 21
0
        public async void ShouldCreatePoAndTransferFunds()
        {
            // Prepare a new PO
            Buyer.Po poAsRequested = await CreateBuyerPoAsync(quoteId : GetRandomInt());

            var signature = poAsRequested.GetSignatureBytes(_contracts.Web3);

            //----------------------------------------------------------
            // BEFORE PO RAISED
            //----------------------------------------------------------
            // Balance of Web3, before test starts (check account running these tests has enough funds to pay for the PO)
            StandardTokenService sts = new StandardTokenService(_contracts.Web3, poAsRequested.CurrencyAddress);
            var totalPoValue         = poAsRequested.GetTotalCurrencyValue();
            var web3AddressBalance   = await sts.BalanceOfQueryAsync(_contracts.Web3.TransactionManager.Account.Address);

            web3AddressBalance.Should().BeGreaterOrEqualTo(totalPoValue, "the Web3 account must be able to pay for whole PO");
            _output.WriteLine($"PO: {poAsRequested.PoNumber}  total value {await totalPoValue.PrettifyAsync(sts)}");

            // Balance of BuyerWallet, before test starts
            var buyerWalletBalance = await sts.BalanceOfQueryAsync(poAsRequested.BuyerWalletAddress);

            _output.WriteLine($"Wallet Buyer balance before test: {await buyerWalletBalance.PrettifyAsync(sts)}");

            // Test setup - transfer required funds from current Web3 acccount to wallet buyer
            var txTransfer = await sts.TransferRequestAndWaitForReceiptAsync(poAsRequested.BuyerWalletAddress, totalPoValue);

            txTransfer.Status.Value.Should().Be(1);

            // Balance of BuyerWallet, before PO raised
            buyerWalletBalance = await sts.BalanceOfQueryAsync(poAsRequested.BuyerWalletAddress);

            _output.WriteLine($"Wallet Buyer balance after receiving funding from Web3 account: {await buyerWalletBalance.PrettifyAsync(sts)}");

            // Balance of Funding, before PO raised
            var fundingBalanceBefore = await sts.BalanceOfQueryAsync(_contracts.Deployment.FundingService.ContractHandler.ContractAddress);

            _output.WriteLine($"Funding balance before PO: {await fundingBalanceBefore.PrettifyAsync(sts)}");

            //----------------------------------------------------------
            // RAISE PO
            //----------------------------------------------------------
            // Create PO on-chain
            // NB this approves token transfer from WALLET BUYER contract (NOT msg.sender == current web3 account) to FUNDING contract
            var txReceiptCreate = await _contracts.Deployment.BuyerWalletService.CreatePurchaseOrderRequestAndWaitForReceiptAsync(poAsRequested, signature);

            txReceiptCreate.Status.Value.Should().Be(1);
            _output.WriteLine($"... PO created ...");

            //----------------------------------------------------------
            // AFTER PO RAISED
            //----------------------------------------------------------
            // Balance of BuyerWallet, after PO raised
            buyerWalletBalance = await sts.BalanceOfQueryAsync(poAsRequested.BuyerWalletAddress);

            _output.WriteLine($"Wallet Buyer balance after PO: {await buyerWalletBalance.PrettifyAsync(sts)}");

            // Balance of Funding, after PO raised
            var fundingBalanceAfter = await sts.BalanceOfQueryAsync(_contracts.Deployment.FundingService.ContractHandler.ContractAddress);

            _output.WriteLine($"Funding balance after PO: {await fundingBalanceAfter.PrettifyAsync(sts)}");

            // Check
            var diff = fundingBalanceAfter - fundingBalanceBefore;

            diff.Should().Be(totalPoValue, "funding contract should have increased in value by the PO value");
        }
Ejemplo n.º 22
0
 // PoStorage <=> Buyer
 public static Storage.Po ToStoragePo(this Buyer.Po po)
 {
     return(_mapper.Map <Storage.Po>(po));
 }
Ejemplo n.º 23
0
 public static Seller.Po ToSellerPo(this Buyer.Po po)
 {
     return(_mapper.Map <Seller.Po>(po));
 }
Ejemplo n.º 24
0
 public static Purchase.Po ToPurchasingPo(this Buyer.Po po)
 {
     return(_mapper.Map <Purchase.Po>(po));
 }
Ejemplo n.º 25
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");
        }