How to implement order versioning in Hybris? - e-commerce

I have requirement in Hybris as when user will place any order we are submitting order to SAP by cron job and SAP is processing the order and updating back to Hybris with updated order number and other details. We want to keep the original copy in Hybris how to achieve this?

When you create a snapshot Hybris create a deep copy of the Order (creates a copy of all sub-elements), to differentiate snapshots and original orders Hybris adds a versionID and a reference to the origin version to snapshots (originalVersion, versionId). From the origin Order you can see the list of all snapshots from the Order History Tab.
From the HMC you will see all duplicated orders but from a user perspective you will see only the original versions as the Customer Account DAO only loads Orders without versionID '{" + OrderModel.VERSIONID + "} IS NULL'
Example using Groovy :
import de.hybris.platform.orderhistory.OrderHistoryService
import de.hybris.platform.servicelayer.search.FlexibleSearchService
import de.hybris.platform.store.services.BaseStoreService
import de.hybris.platform.core.model.order.OrderModel
import de.hybris.platform.core.model.user.UserModel
import de.hybris.platform.orderhistory.model.OrderHistoryEntryModel
import de.hybris.platform.servicelayer.model.ModelService
import de.hybris.platform.servicelayer.user.UserService
import java.util.Collection
import java.util.Iterator
import de.hybris.platform.store.BaseStoreModel
import de.hybris.platform.commerceservices.customer.dao.CustomerAccountDao
BaseStoreService bss = spring.getBean("baseStoreService")
UserService us = spring.getBean("userService")
FlexibleSearchService fss = spring.getBean("flexibleSearchService")
OrderHistoryService ohs =spring.getBean("orderHistoryService")
ModelService ms = spring.getBean("modelService")
CustomerAccountDao cad = spring.getBean("customerAccountDao")
BaseStoreModel baseStore = bss.getBaseStoreForUid("electronics")
UserModel user = userService.getUserForUID("customerUID")
Collection<OrderModel> orders = user.getOrders()
OrderModel order = cad.findOrderByCodeAndStore("orderCode", baseStore)
OrderModel orderSnap = ohs.createHistorySnapshot(order)
OrderHistoryEntryModel entry = modelService.create(OrderHistoryEntryModel.class)
entry.setTimestamp(new Date())
entry.setOrder(order)
entry.setDescription("Took a snap")
entry.setPreviousOrderVersion(orderSnap)
ohs.saveHistorySnapshot(orderSnap)
modelService.saveAll( order, entry, orderSnap )
OrderHistoryService :
public abstract interface OrderHistoryService
{
public abstract OrderModel createHistorySnapshot(OrderModel paramOrderModel);
public abstract void saveHistorySnapshot(OrderModel paramOrderModel);
public abstract Collection<OrderModel> getHistorySnapshots(OrderModel paramOrderModel);
public abstract Collection<OrderHistoryEntryModel> getHistoryEntries(OrderModel paramOrderModel, Date paramDate1, Date paramDate2);
public abstract Collection<String> getHistoryEntriesDescriptions(OrderModel paramOrderModel, Date paramDate1, Date paramDate2);
public abstract Collection<OrderHistoryEntryModel> getHistoryEntries(OrderModel paramOrderModel, EmployeeModel paramEmployeeModel);
public abstract Collection<OrderHistoryEntryModel> getHistoryEntries(UserModel paramUserModel, Date paramDate1, Date paramDate2);
}

In order to create order versioning there are just two steps to accomplish:
creating a new OrderHistoryEntry
Create and attach a snapshot.
more details are here

Related

Spring Webflux send event when any new data

I'm trying to learn Spring webflux & R2DBC. The one I try is simple use case:
have a book table
create an API (/books) that provides text stream and returning Flux<Book>
I'm hoping when I hit /books once, keep my browser open, and any new data inserted to book table, it will send the new data to browser.
Scenario 2, still from book table:
have a book table
create an API (/books/count) that returning count of data in book as Mono<Long>
I'm hoping when I hit /books/count once, keep my browser open, and any new data inserted /deleted to book table, it will send the new count to browser.
But it does not works. After I isnsert new data, no data sent to any of my endpoint.
I need to hit /books or /books/count to get the updated data.
I think to do this, I need to use Server Sent Events? But how to do this in and also querying data? Most sample I got is simple SSE that sends string every certain interval.
Any sample to do this?
Here is my BookApi.java
#RestController
#RequestMapping(value = "/books")
public class BookApi {
private final BookRepository bookRepository;
public BookApi(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
#GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<Book> getAllBooks() {
return bookRepository.findAll();
}
#GetMapping(value = "/count", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Mono<Long> count() {
return bookRepository.count();
}
}
BookRepository.java (R2DBC)
import org.springframework.data.r2dbc.repository.R2dbcRepository;
public interface BookRepository extends R2dbcRepository<Book, Long> {
}
Book.java
#Table("book")
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Book {
#Id
private Long id;
#Column(value = "name")
private String name;
#Column(value = "author")
private String author;
}
Use a Processor or Sink to handle the Book created event.
Check my example using reactor Sinks, and read this article for the details.
Or use a tailable Mongo document.
A tailable MongoDB document can do the work automatically, check the main branch of the same repos.
My above example used the WebSocket protocol, it is easy to switch to SSE, RSocket.
Below Post would help you to achieve your first requirement
Spring WebFlux (Flux): how to publish dynamically
Let me know , if that helps you

How to find last 10 entity whose specific columns is different in Croud Repository?

I'm developing a backend application on Spring Boot 2 and Croud Repository.
I have a table called MoneyTransfer, and table has columns called customerId and firmId.
I need to get last 10 different firms that customer transferred money.
Currently, I get users all money transfers and filter them. However, this method doesn't make sense because I get all elements in the database to find last 10. It may cause performance problem.
fun getList(customerId: String) {
var list = mutableListOf<MoneyTransfer>()
moneyTransferRepository.findByCustomerId(customerId).forEach {
if (list.find(elem -> it.firmId == elem.firmId) == null) {
list.add(it)
}
if (list.size == 10) {
return#forEach
}
}
return list
}
Do you have any efficient solutuion that let me get last 10 different firmId without getting all database row?
If you are using Spring Data along with Spring Boot, you can create a SQL Query to retrieve only the records you want and use it with #Query annotations.
For example:
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}
Documentation here: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.at-query
Create custom #Query with pagination, this will help you optimize the query without getting all database row
#Repository
public interface MoneyTransferRepository extends CrudRepository<MoneyTransfer, String> {
#Query("SELECT m.firmId FROM MoneyTransfer m WHERE m.customerId = :customerId ORDER BY m.id DESC")
List<String> findFirmIdsByCustomerId(#Param("customerId") String customerId, Pageable pageable);
}
But you still will have to check the result with deferent firmId and check the result size of deferent firmIds, if it's less than 10 then in your case you will again make a request to the database and change page in PageRequest
moneyTransferRepository.findFirmIdsByCustomerId(customerId, PageRequest.of(0, 10));
P.S. I also tried this with DISTINCT but it ignores all duplicated firmId with the same customerId
Try this way (i'm not sure - can not test right now)
public interface MoneyTransferRepository extends JpaRepository<MoneyTransfer, Long> {
MoneyTransfer findFirst10ByCustomerIdDesc(String customerId);
}
And sort result reverse in getList method

Sonar Custom Widget

I created a widget using the source code available in github. Now I'm using that widget in SonarQube V5.3. This is where I got the source code from:
https://github.com/SonarSource/sonar-examples/tree/master/plugins/sonar-reference-plugin
When I use this widget it is showing up the same data across multiple projects. I would like to know if there is any way I can display different data for different projects. Please share your ideas. Below is the code that displays the ruby widget
import org.sonar.api.web.AbstractRubyTemplate;
import org.sonar.api.web.Description;
import org.sonar.api.web.RubyRailsWidget;
import org.sonar.api.web.UserRole;
import org.sonar.api.web.WidgetCategory;
import org.sonar.api.web.WidgetProperties;
import org.sonar.api.web.WidgetProperty;
import org.sonar.api.web.WidgetPropertyType;
import org.sonar.api.batch.CheckProject;
import org.sonar.api.resources.Project;
#UserRole(UserRole.USER)
#Description("Sample")
#WidgetCategory("Sample")
#WidgetProperties({
#WidgetProperty(key = "Index",type=WidgetPropertyType.TEXT
),
})
public class OneMoreRubyWidget extends AbstractRubyTemplate implements RubyRailsWidget {
#Override
public String getId() {
return "Sample";
}
#Override
public String getTitle() {
return "Sample";
}
#Override
protected String getTemplatePath() {
return "/example/Index.html.erb";
}
}
Thank you so much in advance
You haven't specified global scope for your widget (#WidgetScope("GLOBAL")) in the .java file, so this is a question of what's in your .erb file.
This Widget Lab property widget should give you some pointers. Specifically: you want to pick up #project in your widget, and query with #project.uuid. Here's another project-level widget for comparison.
You should be aware, though, that SonarSource is actively working to remove Ruby from the platform, so at some future date, you'll probably end up re-writing your widgets (likely in pure JavaScript).

Simple currency observer

I am trying to use the cryptsy.com's API to get the current price of doge. This is my code.
package main;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import main.Cryptsy.CryptsyException;
import main.Cryptsy.PublicMarket;
public class Main {
public static void main (String [] args) throws CryptsyException, InterruptedException{
Cryptsy cryptsy = new Cryptsy();
while(true){
PublicMarket[] markets = cryptsy.getPublicMarketData();
for(PublicMarket market : markets) {
DecimalFormat df = new DecimalFormat("#.########");
if(market.label.equals("DOGE/BTC"))
System.out.println(new Date() + " " + market.label + " " + df.format(market.lasttradeprice));
}
TimeUnit.SECONDS.sleep(30);
}
}
}
the problem is that the price get updated too rear (30 mins or something) and only if I restart my program. Anyone to know how to get the current price? Also there is connection errors sometimes.
Actually the connection problems are normal with the Cryptsy API. It's slow and often disconnects without an answer. They are overcrowded like all the times.
There is a new API location that should be faster and solve the connection issies, here:
http://pubapi.cryptsy.com/api.php?method=marketdatav2
And also, if you are only interested in one single currency, you can get the market data of only that currency. The whole Answer from Cryptsy for all Currencies is like 300k, so you would waste bandwith, if you poll that every minute or so.
For only one currency it will be like:
http://pubapi.cryptsy.com/api.php?method=singlemarketdata&marketid={MARKET ID}
Where the market ID can be gathered inside the answer of the first URL. But you just need the int ID of the market once, from then on you can always use the direct call..
Every Detail is BTW available here:
https://www.cryptsy.com/pages/api

Document structure for RavenDB

I have class
class UserActivity
{
private IList<Activity> _activities = new List<Activity>();
public void AddActivity(Activity activity)
{
_activities.Add(activity);
}
public IEnumerable<Activity> ActivityHistory
{
return _activities;
}
}
Activity history can have a lot of elements.
I wish store UserActivity in RavenDB with history. But, when I get UserActivity first time from DB, ActivityHistory should have last 10 items, for example, and I should have possibility load other items or add new to collection and save them.
How I can do it?
As I understand, i have only one way - store apart UserActivity and history items.
Gengzu,
Yes, you need to deal with the document as a whole.
You can project parts of the documents out into an index, but that is a projection, not an entity