Hyperledger fabric composer transaction not working - hyperledger-fabric

I'm trying add this transaction named placeOrder i want to add a Customer participant
before creating Order asset and map its relationship with the Order asset while processing this transaction. But I'm getting customer not defined error. Can anybody help? Thanks.
My models
namespace org.isn.customer
participant Customer identified by email {
o String firstName
o String lastName
o String email
o String password
}
enum Status{
o ACTIVE
o OFF_THE_ROAD
}
asset Vehicle identified by serial {
o String brand
o String model
o String color
o Status status
o Double price
o String serial
}
asset Order identified by orderId{
o String orderId
o Vehicle item
--> Customer customer
}
transaction PlaceOrder {
o String orderId
--> Vehicle item
o Customer customer
}
script.js
/**
* #param {org.isn.shop.PlaceOrder}orderRequest
* #transaction
*/
async function placeOrder(orderRequest){
const factory = getFactory();
const customerRegistry = await getParticipantRegistry("org.isn.customer.Customer");
const customerExists = await customerRegistry.exists(orderRequest.customer.email);
if(!customerExists){
const customer = factory.newResource("org.isn.customer","Customer",orderRequest.customer.email);
customer.firstName = orderRequest.customer.firstName;
customer.lastName = orderRequest.customer.lastName;
customer.email = orderRequest.customer.email;
customer.password = orderRequest.customer.password;
await customerRegistry.add(customer);
}else{
const customer = await customerRegistry.get(orderRequest.customer.email);
}
const order = await factory.newResource("org.isn.shop","Order",orderRequest.orderId);
order.customer = customer.getIdentifier();
order.item = orderRequest.item;
const orderRegistry = await getAssetRegistry("org.isn.shop.Order");
await orderRegistry.add(order);
const PlaceOrderEvent = factory.newEvent("org.isn.shop","PlaceOrderEvent");
placeOrderEvent.order = order;
emit(placeOrderEvent);
}

o Customer customer needs to become --> Customer customer then you will be able to reference orderRequest.customer.firstName etc also not sure you need order.customer = customer.getIdentifier(); might need to become order.customer.email = customer.getIdentifier();

The following version of the Model and the JS will work for a new and existing customer:
namespace org.isn.customer
participant Customer identified by email {
o String firstName
o String lastName
o String email
o String password
}
enum Status{
o ACTIVE
o OFF_THE_ROAD
}
asset Vehicle identified by serial {
o String brand
o String model
o String color
o Status status
o Double price
o String serial
}
asset Order identified by orderId{
o String orderId
--> Vehicle item
--> Customer customer
}
transaction PlaceOrder {
o String orderId
--> Vehicle item
o Customer customer
}
/**
* #param {org.isn.customer.PlaceOrder}orderRequest
* #transaction
*/
async function placeOrder(orderRequest){
const factory = getFactory();
const customerRegistry = await getParticipantRegistry("org.isn.customer.Customer");
const customerExists = await customerRegistry.exists(orderRequest.customer.email);
if(!customerExists){
var customer = factory.newResource("org.isn.customer","Customer",orderRequest.customer.email);
customer.firstName = orderRequest.customer.firstName;
customer.lastName = orderRequest.customer.lastName;
customer.email = orderRequest.customer.email;
customer.password = orderRequest.customer.password;
await customerRegistry.add(customer);
}else{
var customer = await customerRegistry.get(orderRequest.customer.email);
}
const order = await factory.newResource("org.isn.customer","Order",orderRequest.orderId);
order.customer = factory.newRelationship("org.isn.customer","Customer",customer.getIdentifier());
order.item = orderRequest.item;
const orderRegistry = await getAssetRegistry("org.isn.customer.Order");
await orderRegistry.add(order);
}
Please note the following:
In the Order asset I have changed the o Vehicle to be --> Vehicle item to match up with the Transaction.
I have also used var customer in both the if and else code.
(To make mine work I had to use the same namespace, but perhaps you had separate .cto files)

Related

How to update the relationship values inside transaction processor functions?

I have a model file org.acme.interm.container.cto which looks something like this :
namespace org.acme.interm.container
asset Container identified by containerId {
o String containerId regex=/[A-Z][A-Z][0-9][0-9][0-9]-[0-9][0-9]-[0-3][0-9]-[0-9][0-9]/
o String containerNumber
--> Truck truck optional
}
asset Truck identified by truckId {
o String truckId
o Ownership ownershipType default="LEASED"
o Integer normalWeight range = [,100]
o Integer fragileWeight range = [,50]
}
enum Ownership {
o LEASED
o OWNED
}
transaction AssignTruck {
o String containerId
o String truckId
}
event TruckAssigned {
o String containerId
o String truckId
}
transaction LoadContainer {
o String containerId
--> Truck truck
o Integer fragileWeight
o Integer normalWeight
}
I am assigning the Truck relation to the container asset in the following transaction :
function AssignTruck(containerTruckData) {
console.log("ASSIGN TRUCK CALLED!");
var containerRegistry={}
return getAssetRegistry('org.acme.interm.container.Container').then(function(registry){
containerRegistry = registry
return containerRegistry.get(containerTruckData.containerId);
}).then(function(container){
console.log("Got Container",container);
if(!container) throw new Error("Container : "+containerTruckData.containerId," Not Found!!!");
var factory = getFactory();
var relationship = factory.newRelationship('org.acme.interm.truck','Truck',containerTruckData.truckId);
container.truck = relationship;
return containerRegistry.update(container);
}).then(function(){
// Successful update
var event = getFactory().newEvent('org.acme.interm.container', 'TruckAssigned');
event.containerId = containerTruckData.containerId;
event.truckId = containerTruckData.truckId;
emit(event);
}).catch(function(error){
throw new Error(error);
});
}
Now, how can i write the loadContainer transaction, where the existing values of normalWeight and fragileWeight properties of the container(for given containerId) should be added to the newly passed fragileWeight and normalWeight
values?
Firstly unless each container has a weight variable, it is impossible to track the individual weight. Even if you keep updating the weight in the trucks, you will know the collective weight of containers which is not enough. Especially if you want to unload containers. I would suggest this approach
asset Container identified by containerId {
o String containerId regex=/[A-Z][A-Z][0-9][0-9][0-9]-[0-9][0-9]-[0-3][0-9]-[0-9][0-9]/
o String containerNumber
o Integer normalWeight range = [,100]
o Integer fragileWeight range = [,50]
--> Truck truck optional
}
asset Truck identified by truckId {
o String truckId
o Ownership ownershipType default="LEASED"
o Integer totalNormalWeight range default=0
o Integer totalFragileWeight range default=0
--> Container containersLoaded[] optional
}
So this will let you track weight per container and then add them to get the total in truck. The containersLoaded variable will let you keep track of containers loaded. An advantage of this is, you can accurately reduce the weight if a container is unloaded or split (which I assume will be part of the user flow)
function AssignTruck(containerTruckData) {
var myContainer; // store data from the promise
var myTruck;
console.log("ASSIGN TRUCK CALLED!");
var containerRegistry={}
var truckRegistry;
return getAssetRegistry('org.acme.interm.container.Container').then(function(registry){
containerRegistry = registry
return containerRegistry.get(containerTruckData.containerId);
}).then(function(container){
console.log("Got Container",container);
myContainer = container;
if(!container) throw new Error("Container : "+containerTruckData.containerId," Not Found!!!");
var factory = getFactory();
var relationship = factory.newRelationship('org.acme.interm.truck','Truck',containerTruckData.truckId);
container.truck = relationship;
return containerRegistry.update(container);
}).then(function() {
return getAssetRegistry('org.acme.interm.truck.Truck');
}).then(function (truckRegistry) {
truckRegistry = truckRegistry;
return truckRegistry.get(containerTruckData.truckId);
}).then(function (truck) {
truck.totalNormalWeight += myContainer.normalWeight;
truck.totalFragileWeight += myContainer.fragileWeight;
if (!truck.containersLoaded) {
truck.containersLoaded = [];
} else {
truck.containersLoaded.push(factory.newRelationship('org.acme.interm.container', 'Container', myContainer.containerId))
};
return truckRegistry.update(truck)
}).then(function(){
// Successful update
var event = getFactory().newEvent('org.acme.interm.container', 'TruckAssigned');
event.containerId = containerTruckData.containerId;
event.truckId = containerTruckData.truckId;
emit(event);
}).catch(function(error){
throw new Error(error);
});
}
This should work for you. Now you can query the truck and get total weight of all containers by checking the totalNormalWeight and totalFragileWeight variables. You can also check the containersLoaded array to get the list of the containers. To get the individual weight of the a container, either you can query the container and get its weight or get it directly from the containersLoaded variable.
When the containers need to be removed/ unloaded from the truck, you can get their individual weight and subtract from the total, and pop the relationship from the containersLoaded.

How to get history of transactions for particular Asset in hyperledger composer?

I have tried below code but i am unable to get transaction history for Specific Asset Can any one help me regarding this issue.
#commit(false)
#returns(Order[])
transaction orderHistory {
o String orderNumber
}enter code here
/**
* Sample transaction
* #param {org.acme.Block.orderHistory} purchase
* #transaction
*/
async function orderHistory(transaction) {
const orderNumber = purchase.orderNumber;
const nativeSupport = purchase.nativeSupport;
const assetRegistry = await getAssetRegistry('org.acme.Block.Order')
const nativeKey = getNativeAPI().createCompositeKey('Asset:org.acme.Block.Order', [orderNumber]);
console.log(nativeKey);
const iterator = await getNativeAPI().getHistoryForKey(nativeKey);
let results = [];
let res = {done : false};
while (!res.done) {
res = await iterator.next();
if (res && res.value && res.value.value) {
console.log(res);
let val = res.value.value.toString('utf8');
if (val.length > 0) {
results.push(JSON.parse(val));
}
}
if (res && res.done) {
try {
iterator.close();
}
catch (err) {
}
}
}
return results;
In hyperledger composer, all the transactions are stored in a Historian Record (https://hyperledger.github.io/composer/unstable/reference/historian.html). So querying and using the same will resolve your problem. Historian record is an asset defined in the Hyperledger composer namespace.
Historian record is defined as :
asset HistorianRecord identified by transactionId {
o String transactionId
o String transactionType
--> Transaction transactionInvoked
--> Participant participantInvoking optional
--> Identity identityUsed optional
o Event[] eventsEmitted optional
o DateTime transactionTimestamp
}
You can read more about the Historian Client API which will prove to be useful for you: https://hyperledger.github.io/composer/v0.19/api/client-historian
Also, read this discussion on history of an asset in composer: https://github.com/hyperledger/composer/issues/2458

How to batch get items using servicestack.aws PocoDynamo?

With Amazon native .net lib, batchget is like this
var batch = context.CreateBatch<MyClass>();
batch.AddKey("hashkey1");
batch.AddKey("hashkey2");
batch.AddKey("hashkey3");
batch.Execute();
var result = batch.results;
Now I'm testing to use servicestack.aws, however I couldn't find how to do it. I've tried the following, both failed.
//1st try
var q1 = db.FromQueryIndex<MyClass>(x => x.room_id == "hashkey1" || x.room_id == "hashkey2"||x.room_id == "hashkey3");
var result = db.Query(q1);
//2nd try
var result = db.GetItems<MyClass>(new string[]{"hashkey1","hashkey2","hashkey3"});
In both cases, it threw an exception that says
Additional information: Invalid operator used in KeyConditionExpression: OR
Please help me. Thanks!
Using GetItems should work as seen with this Live Example on Gistlyn:
public class MyClass
{
public string Id { get; set; }
public string Content { get; set; }
}
db.RegisterTable<MyClass>();
db.DeleteTable<MyClass>(); // Delete existing MyClass Table (if any)
db.InitSchema(); // Creates MyClass DynamoDB Table
var items = 5.Times(i => new MyClass { Id = $"hashkey{i}", Content = $"Content {i}" });
db.PutItems(items);
var dbItems = db.GetItems<MyClass>(new[]{ "hashkey1","hashkey2","hashkey3" });
"Saved Items: {0}".Print(dbItems.Dump());
If your Item has both a Hash and a Range Key you'll need to use the GetItems<T>(IEnumerable<DynamoId> ids) API, e.g:
var dbItems = db.GetItems<MyClass>(new[]{
new DynamoId("hashkey1","rangekey1"),
new DynamoId("hashkey2","rangekey3"),
new DynamoId("hashkey3","rangekey4"),
});
Query all Items with same HashKey
If you want to fetch all items with the same HashKey you need to create a DynamoDB Query as seen with this Live Gistlyn Example:
var items = 5.Times(i => new MyClass {
Id = $"hashkey{i%2}", RangeKey = $"rangekey{i}", Content = $"Content {i}" });
db.PutItems(items);
var rows = db.FromQuery<MyClass>(x => x.Id == "hashkey1").Exec().ToArray();
rows.PrintDump();

Paypal error when processing credit card mvc 5

I'm attempting to process creit cards through PayPal and keep getting this weird error:
{"name":"VALIDATION_ERROR","details":[{"field":"transactions[0].amount","issue":"Transaction
amount details (subtotal, tax, shipping) must add up to specified
amount total"}],"message":"Invalid request - see
details","information_link":"https://developer.paypal.com/webapps/developer/docs/api/#VALIDATION_ERROR","debug_id":"6e2cef39d556a"}
Here's the method I'm using:
public ActionResult PaymentWithCreditCard(PayWithCCViewModel model)
{
var cart = ShoppingCart.GetCart(this.HttpContext);
var cartItems = cart.GetCartItems();
List<Item> orderItems = new List<Item>();
foreach (var cartItem in cartItems)
{
var item = new Item();
item.name = cartItem.Product.ProductName;
item.currency = "USD";
item.price = cartItem.ProductPrice.ToString();
item.quantity = cartItem.ProductQuantity.ToString();
orderItems.Add(item);
}
ItemList itemList = new ItemList();
itemList.items = orderItems;
//Address for the payment
Address billingAddress = new Address();
billingAddress.city = model.BillingCity;
billingAddress.country_code = "US";
billingAddress.line1 = model.BillingAddressLine1;
billingAddress.line2 = model.BillingAddressLine2;
billingAddress.postal_code = model.BillingPostalCode;
billingAddress.state = model.BillingState;
//Now Create an object of credit card and add above details to it
CreditCard card = new CreditCard();
card.billing_address = billingAddress;
card.cvv2 = model.CVV2;
card.expire_month = model.ExpirationMonth;
card.expire_year = model.ExpirationYear;
card.first_name = model.FirstName;
card.last_name = model.LastName;
card.number = model.Number;
card.type = model.CardType.ToString();
var subTotal = cart.GetTotal();
var tax = Convert.ToDouble(subTotal) * Convert.ToDouble(.076);
var total = Convert.ToDouble(subTotal) + tax;
// Specify details of your payment amount.
Details details = new Details();
details.shipping = "3";
details.subtotal = subTotal.ToString();
details.tax = tax.ToString();
// Specify your total payment amount and assign the details object
Amount amount = new Amount();
amount.currency = "USD";
// Total = shipping tax + subtotal.
amount.total = total.ToString();
amount.details = details;
// Now make a trasaction object and assign the Amount object
Transaction transaction = new Transaction();
transaction.amount = amount;
transaction.description = "Payment to AccessorizeForLess.net";
transaction.item_list = itemList;
transaction.invoice_number = cart.GetCartId(this.HttpContext);
// Now, we have to make a list of trasaction and add the trasactions object
// to this list. You can create one or more object as per your requirements
List<Transaction> transactions = new List<Transaction>();
transactions.Add(transaction);
// Now we need to specify the FundingInstrument of the Payer
// for credit card payments, set the CreditCard which we made above
FundingInstrument fundInstrument = new FundingInstrument();
fundInstrument.credit_card = card;
// The Payment creation API requires a list of FundingIntrument
List<FundingInstrument> fundingInstrumentList = new List<FundingInstrument>();
fundingInstrumentList.Add(fundInstrument);
// Now create Payer object and assign the fundinginstrument list to the object
Payer payr = new Payer();
payr.funding_instruments = fundingInstrumentList;
payr.payment_method = "credit_card";
// finally create the payment object and assign the payer object & transaction list to it
Payment pymnt = new Payment();
pymnt.intent = "sale";
pymnt.payer = payr;
pymnt.transactions = transactions;
try
{
//getting context from the paypal, basically we are sending the clientID and clientSecret key in this function
//to the get the context from the paypal API to make the payment for which we have created the object above.
// Basically, apiContext has a accesstoken which is sent by the paypal to authenticate the payment to facilitator account. An access token could be an alphanumeric string
APIContext context = PayPalModel.GetAPIContext();
// Create is a Payment class function which actually sends the payment details to the paypal API for the payment. The function is passed with the ApiContext which we received above.
Payment payment = pymnt.Create(context);
//if the createdPayment.State is "approved" it means the payment was successfull else not
if (payment.state.ToLower() != "approved")
{
return View("FailureView");
}
}
catch (PayPalException ex)
{
Logger.Log("Error: " + ex.Message);
return View("FailureView");
}
return View("SuccessView");
}
I've stepped through the code and the total, tax and shipping seem to be correct, anyone have issues when dealing with PayPal before that could led me t a solution?
I forgot to add shipping to the total, now I get an approval

PaymentAmount does not match line deposit plus +credit card payment total

Using the Dynamics GP Web Service API on GP 2013, how do I apply payments to a Sales Invoice? I receive the error in the subject line. Here is my code:
static void CreateInvoice()
{
CompanyKey companyKey;
Context context;
SalesInvoice salesInvoice;
SalesDocumentTypeKey salesInvoiceType;
CustomerKey customerKey;
BatchKey batchKey;
SalesInvoiceLine salesInvoiceLine;
ItemKey invoiceItem;
Quantity invoiceCount;
Policy salesInvoiceCreatePolicy;
// Create an instance of the service
DynamicsGP wsDynamicsGP = new DynamicsGP();
// Be sure the default credentials are used
wsDynamicsGP.UseDefaultCredentials = true;
// Create a context with which to call the service
context = new Context();
// Specify which company to use (sample company)
companyKey = new CompanyKey();
companyKey.Id = (-1);
// Set up the context object
context.OrganizationKey = (OrganizationKey)companyKey;
// Create a sales invoice object
salesInvoice = new SalesInvoice();
// Create a sales document type key for the sales invoice
salesInvoiceType = new SalesDocumentTypeKey();
salesInvoiceType.Type = SalesDocumentType.Invoice;
// Populate the document type key for the sales invoice
salesInvoice.DocumentTypeKey = salesInvoiceType;
// Create a customer key
customerKey = new CustomerKey();
customerKey.Id = "ADMINISTRATORGL";
// Set the customer key property of the sales invoice
salesInvoice.CustomerKey = customerKey;
// Create a batch key
batchKey = new BatchKey();
batchKey.Id = "SALES INVOICES";
// Set the batch key property of the sales invoice object
salesInvoice.BatchKey = batchKey;
// Create a sales invoice line to specify the invoiced item
salesInvoiceLine = new SalesInvoiceLine();
// Create an item key
invoiceItem = new ItemKey();
invoiceItem.Id = "ADI123";
// Set the item key property of the sales invoice line object
salesInvoiceLine.ItemKey = invoiceItem;
// Create a sales invoice quatity object
invoiceCount = new Quantity();
invoiceCount.Value = 2;
// Set the quantity of the sales invoice line object
salesInvoiceLine.Quantity = invoiceCount;
salesInvoiceLine.WarehouseKey = new WarehouseKey { Id = "NORTH" };
// Create an array of sales invoice lines
// Initialize the array with the sales invoice line object
SalesInvoiceLine[] invoiceLines = { salesInvoiceLine };
// Add the sales invoice line array to the sales line object
salesInvoice.Lines = invoiceLines;
//salesInvoice.LineTotalAmount = new MoneyAmount { Value = 399.96M };
salesInvoice.DepositAmount = new MoneyAmount { Value = 399.96M };
salesInvoice.PaymentAmount = new MoneyAmount { Value = 399.96M };
// Get the create policy for the sales invoice object
salesInvoiceCreatePolicy = wsDynamicsGP.GetPolicyByOperation("CreateSalesInvoice", context);
// Create the sales invoice
wsDynamicsGP.CreateSalesInvoice(salesInvoice, context, salesInvoiceCreatePolicy);
}
I had to create a customer and set the credit limit to unlimited.
//assign unlimited class
CustomerCreditLimit cc = new CustomerCreditLimit();
cc.Item = CreditLimitSpecialAmount.UnlimitedCredit;
customer.CreditLimit = cc;
My blog post has more details on the code:
http://www.jmawebtechnologies.com/company-blog/may-2013/appying-payments-to-sales-invoices-and-sales-order

Resources