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()); }
[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); }
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); }
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); }
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); }
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)); }
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"); }
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 }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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"); }
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"); }