Explanation of the various Order Status for NopCommerce - nopcommerce

What are the meanings of the following order statuses (in terms of business process, not from c# point of view)? When each of them are used? Can anyone help me with this? I'm totally new to NOP Commerece. I didn't find any explanation of them.
public enum OrderStatus : int
{
Pending = 10,
Processing = 20,
SentToFullfillment = 25,
Complete = 30,
Cancelled = 40,
FullfillmentError = 50,
ShippingError = 60,
}

The actual code of OrderStatus is:
public enum OrderStatus
{
Pending = 10,
Processing = 20,
Complete = 30,
Cancelled = 40
}
In business term, Pending means the order placed by customer. Once the order in process to shipping, the status change to Processing.
After delivered the order to the customer, store owner mark that order as Complete.
And if customer cancel the order then order status would be Cancelled.

Related

How to get transfer data from stripe using payment id and account id (.Net)

I am trying to get transfer related data from stripe
TransferService service = new TransferService();
TransferListOptions stripeTransferList = new TransferListOptions
{
Destination = accountId,
Limit = 100
};
var list = await service.ListAsync(stripeTransferList);
var finalData = list.FirstOrDefault(x => x.DestinationPaymentId == paymentId);
so when I try to search paymentId from that list I was not able to find any because the page limit is 100 only
Limit = 100
how to fetch all the data and filter from that??
The stripe-dotnet library supports automatic pagination and it's documented here.
This lets you paginate through all the data in your account based on specific criteria that you passed as parameters. For example you can list all Transfer objects made to a specific connected account this way:
TransferService service = new TransferService();
TransferListOptions listOptions = new TransferListOptions
{
Destination = "acct_123456",
Limit = 100
};
foreach (var transfer in service.ListAutoPaging(listOptions)) {
// Do something with this Transfer
}
Now, this allows you to iterate over every Transfer but if you have a lot of data this could be quite slow. An alternative would be to start from the charge id, the py_123456 that you have from your connected account. If you know which account this charge was created on, you can fetch it directly via the API. This is done using the Retrieve Charge API along with passing the connected account id as documented here.
The Charge resource has the source_transfer property which is the id of the Transfer (tr_123) from the platform that created this charge. You can also use the Expand feature, which lets you fetch the entire Transfer object back to get some detailed information about it.
The code would look like this
var transferOptions = new TransferGetOptions{};
transferOptions.AddExpand("source_transfer");
var requestOptions = new RequestOptions();
requestOptions.StripeAccount = "acct_12345";
TransferService service = new TransferService();
Charge charge = service.Get(transferOptions, requestOptions);
// Access information about the charge or the associated transfer
var transferId = charge.SourceTransfer.Id;
var transferAmount = charge.SourceTransfer.TransferData.Amount;

In CyberSource, how do you use a credit card flexible token with payments API?

Trying to get my head around how CyberSource works..
In CyberSource, the Secure Acceptance Flexible Token API can be used to tokenize a credit card on client-side for processing for future processing.
That part is easy enough. There's plenty of documentation and a few packages that do it.
How do I then use that token to create a charge with the CyberSource Payments API ?
All examples i've found show how to tokenize the card on client, and how to charge an untokenized card (i.e. card data is sent to server) but I can't find an example that show how to use the Flexible token to create a charge (or pre-auth).
In most other gateways like Stripe, it's pretty clear in documentations but CyberSource doesn't seem to provide that.
Am I missing something?
I'm using Node but happy with solutions in other languages.
https://developer.cybersource.com/api-reference-assets/index.html#flex
https://developer.visa.com/capabilities/cybersource/reference
Ok, thanks to #rhldr for pointing out to this particular documentation.
The answer is in this page https://developer.cybersource.com/api/developer-guides/dita-flex/SAFlexibleToken/FlexMicroform/GetStarted.html under "Using the Token".
Note: Some of the other documentations (not sure why they have some many variations of the docs), like this one don't mention this at all.
See the RESTPaymentAPI section. It needs to be provided as a customerId field.
"paymentInformation": {
"customer": {
"customerId": "7500BB199B4270EFE05340588D0AFCAD"
}
}
Here's a minimal example of how it can be implemented on the API side
var cybersourceRestApi = require('cybersource-rest-client');
var configuration = require('./cybersource/config.js');
var configObject = new configuration();
var instance = new cybersourceRestApi.PaymentsApi(configObject);
var clientReferenceInformation = new cybersourceRestApi.Ptsv2paymentsClientReferenceInformation();
clientReferenceInformation.code = 'test_payment';
var processingInformation = new cybersourceRestApi.Ptsv2paymentsProcessingInformation();
processingInformation.commerceIndicator = 'internet';
var amountDetails = new cybersourceRestApi.Ptsv2paymentsOrderInformationAmountDetails();
amountDetails.totalAmount = "100.00";
amountDetails.currency = 'USD';
var orderInformation = new cybersourceRestApi.Ptsv2paymentsOrderInformation();
orderInformation.amountDetails = amountDetails;
var paymentInformation = new cybersourceRestApi.Ptsv2paymentsPaymentInformation();
// THIS IS THE IMPORTANT BIT
var customer = new cybersourceRestApi.Ptsv2paymentsPaymentInformationCustomer()
customer.customerId = token
paymentInformation.customer = customer
var request = new cybersourceRestApi.CreatePaymentRequest();
request.clientReferenceInformation = clientReferenceInformation;
request.processingInformation = processingInformation;
request.orderInformation = orderInformation;
request.paymentInformation = paymentInformation;
if (!authoriseOnly) {
request.processingInformation.capture = true;
}
Code based on the CyberSource nodejs REST samples: https://github.com/CyberSource/cybersource-rest-samples-node
More info. Once you know where to look, it's actually explained in a few places.
Example, go to https://developer.cybersource.com/cybs-dev-api-ref/index.html#payments-process-a-payment, expand the "REQUEST FIELD DESCRIPTION" underneath and go to
customer
.. customerId
Unique identifier for the customer's card
and billing information.
When you use Payment Tokenization or Recurring Billing and you include
this value in your request, many of the fields that are normally
required for an authorization or credit become optional.
NOTE When you use Payment Tokenization or Recurring Billing, the value
for the Customer ID is actually the Cybersource payment token for a
customer. This token stores information such as the consumer’s card
number so it can be applied towards bill payments, recurring payments,
or one-time payments. By using this token in a payment API request,
the merchant doesn't need to pass in data such as the card number or
expiration date in the request itself.
See "Payment Tokenization," page 222, and "Recurring Billing," page
225.

Inaccessible Cash State

I am running into an issue with cash states. Basically I have a node that issues itself money and is unable to access an existing state to use for payment/anything. Let’s say this state is 5 dollars, if I issue 10 more, both rpcOps and the servicehub getCashBalances will say that I have 15 dollars. However, any cash flows that try to use more than 10 dollars will tell me I don’t have sufficient balance.
I’ve set up api endpoints for the node to even just exit the cash but it will say that I’m exiting more than I have. When I query the vault with QueryCriteria.VaultQueryCriteria(Vault.StateStatus.UNCONSUMED), I can see the state is there, and there doesn’t seem to be anything that differentiates the inaccessible state from any subsequent accessible states.
Could there be anything I’m overlooking here? The issuers are the same and the owners are hashed but should be the same, as well.
Updated with command / code:
fun selfIssueTime(#QueryParam(value = "amount") amount: Long,
#QueryParam(value = "currency") currency: String): Response {
// 1. Prepare issue request.
val issueAmount = Amount(amount.toLong() * 100, Currency.getInstance(currency))
val notary = rpcOps.notaryIdentities().firstOrNull() ?: throw IllegalStateException("Could not find a notary.")
val issueRef = OpaqueBytes.of(0)
val issueRequest = CashIssueFlow.IssueRequest(issueAmount, issueRef, notary)
val self = myIdentity
// 2. Start flow and wait for response.
val (status, message) = try {
val flowHandle = rpcOps.startFlowDynamic(
CashIssueFlow::class.java,
issueRequest
)
flowHandle.use { it.returnValue.getOrThrow() }
CREATED to "$issueAmount issued to $self."
} catch (e: Exception) {
BAD_REQUEST to e.message
}
// 3. Return the response.
return Response.status(status).entity(message).build()
}
I believe this is fixed via the later version of Corda finance jars. We have developed a couple more CorDapps samples using the currency class, and we did not run into any issue. For example: https://github.com/corda/samples-java/blob/master/Tokens/dollartohousetoken/workflows/src/main/java/net/corda/examples/dollartohousetoken/flows/FiatCurrencyIssueFlow.java#L39
Further more, with the release of the Corda TokenSDk, Currency on Corda has actually a new way to get issue, transfer and redeem. This is done by:
/* Create an instance of the fiat currency token */
TokenType token = FiatCurrency.Companion.getInstance(currency);
/* Create an instance of IssuedTokenType for the fiat currency */
IssuedTokenType issuedTokenType = new IssuedTokenType(getOurIdentity(), token);
/* Create an instance of FungibleToken for the fiat currency to be issued */
FungibleToken fungibleToken = new FungibleToken(new Amount<>(amount, issuedTokenType), recipient, null);
/* Issue the required amount of the token to the recipient */
return subFlow(new IssueTokens(ImmutableList.of(fungibleToken), ImmutableList.of(recipient)));

Multiple Transactions Using Paypal .NET SDK

I have implemented Paypal ASP.NET SDK to carry out payments on my website, where the user pays for the items through their Paypal account.
What I would like to do is seperate products that the user has ordered into different Paypal transactions, so that when the client logs into Paypal they can see them as seperate itemised transactions.
The Paypal SDK suggests that this can be done, since the Transactions object is a collection. This is a snippet of my code where I am attempting to send multiple transactions through:
#region Get products
ItemList itemList = new ItemList();
if (_products.Any())
{
List<Item> payPalItems = _products.Select(p => new Item
{
name = p.Name,
currency = _currency,
price = p.Price.ToString("N"),
quantity = p.Quantity.ToString(),
sku = p.Sku
}).ToList();
itemList.items = payPalItems;
}
#endregion
#region Personal Details
// Address for the payment
Address billingAddress = new Address();
if (_personalDetails != null)
{
billingAddress.line1 = _personalDetails.Address1;
billingAddress.line2 = _personalDetails.Address2;
billingAddress.state = _personalDetails.County;
billingAddress.city = _personalDetails.City;
billingAddress.postal_code = _personalDetails.PostCode;
billingAddress.country_code = _personalDetails.CountryCode;
}
#endregion
#region Payment Amount Details
Details paymentDetails = new Details();
paymentDetails.shipping = _delivery.ToString();
paymentDetails.subtotal = _products.Sum(p => p.Total).ToString("N");
paymentDetails.tax = _tax.ToString();
Amount paymentAmount = new Amount();
paymentAmount.currency = _currency;
// Total must be equal to sum of shipping, tax and subtotal.
paymentAmount.total = ((decimal.Parse(paymentDetails.subtotal) * (100 + _tax) / 100) + _delivery).ToString("N");
paymentAmount.details = paymentDetails;
#endregion
#region Transaction --> Sending multiple transactions here...
// A transaction defines the contract of a payment - what is the payment for and who is fulfilling it.
Transaction trans1 = new Transaction();
trans1.amount = paymentAmount;
trans1.item_list = itemList; // Currently sending the same list of items for testing.
trans1.invoice_number = "Surinder Split Order 1";
Transaction trans2 = new Transaction();
trans2.amount = paymentAmount;
trans2.item_list = itemList; // Currently sending the same list of items for testing.
trans2.invoice_number = "Surinder Split Order 2";
// The Payment creation API requires a list of transactions.
List<Transaction> transactions = new List<Transaction>();
transactions.Add(trans1);
transactions.Add(trans2);
#endregion
When carrying this out, I get the following error response from Paypal: "Only single payment transaction currently supported".
It seems Paypal does not allow the seperation of transactions from one request. If this is the case, is there any other way to carry out what I am trying to achieve?

Entity framework - increase number by 1

I have one row in database to count total user logins
I have tried to increase number by getting the row and adding +1 to it
And i'm not sure about concurrency after I have tried this, counter was increased by 1 and not by 2 as it "should" (if many users will login at the same time)
using(var db = new Database()) {
db.Settings.FirstOrDefault(x => x.Name == "Logins").Counter++;
using(var db2 = new Database()) {
db2.Settings.FirstOrDefault(x => x.Name == "Logins").Counter++;
db2.SaveChanges();
}
db.SaveChanges();
}
Why not make a single table for storing the number of people who have logged in increment the field when someone logs in successfully and decrease when the user logs out. For example for login:
_Users = context.Users.First(aa => aa.UserName.ToUpper() == _UserName.ToUpper() && aa.MDesktop == true);
if (_Users != null)
{
context.LogEntry.FirstOrDefault().Counter++;
context.SaveChanges();
}
This is old but it is still a relevant discussion for new EF developers and it deserves an explanation.
OP's example uses two different DBContext's, effectively OP has defined two different units of work, and importantly, neither of these is aware that the other exists at all.
Lets assume that the current value of the "Logins" setting is 5
For the purposes of this walkthrough lets save the two instances that are requested from Settings into variables outside of the scope of the DB contexts in question:
Setting setting1 = null;
Setting setting2 = null;
using(var db = new Database()) {
// DB: 5, Setting1: null, Setting2: null
// Load the value of setting1 from the database
setting1 = db.Settings.FirstOrDefault(x => x.Name == "Logins");
// DB: 5, Setting1: 5, Setting2: null
// Increment the value of setting1
setting1.Counter++;
// at this point, no changes have been saved yet, the DB still holds the original value for "Logins"
// DB: 5, Setting1: 6, Setting2: null
// Create a new context called DB2
using(var db2 = new Database()) {
// load setting2 from the DB
setting2 = db2.Settings.FirstOrDefault(x => x.Name == "Logins");
// right now setting2 still has a value of 5, the previous change was not yet committed
// DB: 5, Setting1: 6, Setting2: 5
setting2.Counter++;
// DB: 5, Setting1: 6, Setting2: 6
// Save the value of Setting2 back to the database
db2.SaveChanges();
// DB: 6, Setting1: 6, Setting2: 6
// At this point setting1, setting2, and the DB all agree the value is 6.
}
// The context is only aware that we previously set the value of setting1 to 6
// so it issues an update to the DB
db.SaveChanges();
// ultimately this update would not actually change anything.
}
Entity Framework, Unit of Work and Repository data access patterns all exhibit this behaviour, when you create a new DbContext IRepository or IUnitOfWork it is done so in isolation of any others that might exist at the same point in time, there is no difference between instantiating a new context in the same method, or a different thread or even executing on entirely different servers. If you need to implement counters or incremental values there is always a degree of uncertainty when we first cache the value of the field, then increment the value and later write that value back to the database.
To minimise the potential conflict, read the record and save it immediately after, then as a rule always re-query the value of this setting before you use it.
You can call .SaveChanges() multiple times in your logic, in this example simply saving before instantiating the second context, or at least before the second context loaded the record from the DB would have been enough to see the value incremented twice:
using(var db = new Database()) {
db.Settings.FirstOrDefault(x => x.Name == "Logins").Counter++;
db.SaveChanges(); // save it back as soon as we've made the change
using(var db2 = new Database()) {
db2.Settings.FirstOrDefault(x => x.Name == "Logins").Counter++;
db2.SaveChanges();
}
db.SaveChanges();
}
Where possible, you will find the code simpler if you can avoid a schema where an incrementing or counter fields is required, instead you could turn the count logic into a query based solution.
Counters are of course a special case, you could always make direct SQL calls to the database, both for read or increment to ensure that that we bypass any potential caching that might occur with the records through EF.
You could do this as a one liner to increment the value:
dbContext.Database.ExecuteSqlCommand("UPDATE Setting SET[Counter] = IsNull([Counter],0) + 1 WHERE[Name] = 'Logins'");
Or if you want to inspect the new value:
int newCount = dbContext.Database.SqlQuery<int>(#"
UPDATE Setting SET[Counter] = IsNull([Counter],0) + 1
OUTPUT inserted.[Counter]
WHERE [Name] = 'Logins'").First();
If you need to ge tthe current value, and know that it is the most up-to-date then you can simply query it from any context in the same way:
int logins = dbContext.Database.SqlQuery<int>(#"
SELECT [Counter] FROM Setting
WHERE [Name] = 'Logins'").First();
I hope this sheds some light on why your code only incremented the value once, its not a fault in EF, just something that we need to be aware of, once EF has read values form the DB, they are potentially already stale or out of date. If optimistic concurrency is not appropriate for your use case, then you will need to think outside of the box a little bit ;)
the easy approach?
then I'd suggest using a manual transaction in EF Core
ef core transaction docs
Be sure to add an unique constraint of some sort eb. (settings id + logins counter)
using(var transaction = _context.Database.BeginTransaction())
{
try
{
var totalLoginsCounter = _context.Settings.FirstOrDefault(x => x.Name == "Logins").Counter;
totalLoginsCounter += 1;
await _context.SaveChanges();
transaction.Commit();
}
catch
{
commit.RollBack();
}
}
should concurrency happen the request will fail. Because it would try to put duplicate keys which is not possible. then HIGHLY recommend you'd then implement a retry pattern to avoid people not being able to actually login because a number in your database didn't get updated.

Resources