Skip to content

Commit

Permalink
#51 - Update salespoint reference-documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Andreas Zaschka committed Nov 5, 2015
1 parent 6e3d143 commit ee77933
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 56 deletions.
117 changes: 72 additions & 45 deletions src/main/asciidoc/salespoint-reference.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -150,27 +150,30 @@ Library to build HTML web views using natural templating.
- https://spring.io/guides/gs/serving-web-content[Getting stared guide]
- http://www.thymeleaf.org/doc/usingthymeleaf.html[Tutorial]

[[stack.joda-money]]
== JodaMoney
With Salespoint {majorversion} money class and its related components were replaced by the Joda-Money [7] project. Prices and other money values are represented as `org.joda.money.Money` or for more precisison as `org.joda.money.BigMoney` objects. Due to the fact, that all representing objects are immutable, all arithmetic functions produce a new instance.
[[stack.java-money]]
== JavaMoney
With Salespoint {majorversion} money class and its related components were replaced by the Java-Money project. Prices and other money values are represented as `org.javamoney.moneta.Money`. Due to the fact, that all representing objects are immutable, all arithmetic functions produce a new instance.

.Example for JodaMoney operations
====
[source, java]
Java-Money also supports `Currency`. Some currencies are provided through `org.salespointframework.core.Currencies`. But new and funky `CurrencyUnits` can be created too. So with this currencies, money values can be converted from one to another currency.

- http://javamoney.org[Project Home]
- https://github.com/JavaMoney/javamoney-examples[Usage, Examples]

.Usage of JavaMoney
[source,java]
----
Money first = Money.parse(“USD 23.07”);
Money second = Money.parse(“USD 18.07”);
Money sum = first.plus(second);
CurrencyUnit euro = Monetary.getCurrency("EURO"); # <1>
Money money = Money.of(120, euro); # <2>
----
====

Joda-Money also supports `Currency` (see _Example for JodaMoney operations_). A set of loaded currencies is provided by an instance of `CurrencyUnitDataProvider`. But new and funky `CurrencyUnits` can be created to. So with this currencies, money values can be converted from one to another currency.
<1> First create a CurrencyUnit
<2> Second create a Money value of 120 with CurrencyUnit of 'EURO'

[[modules]]
= Business modules

[[modules.useraccount]]
== Users
=== UserAccount

////
[User|-enabled:boolean]-0..*>[Role]
Expand All @@ -183,23 +186,36 @@ image::user-account.png[title="User Account"]
To manage system accounts, Salespoint {majorversion} has a notation of a user in the form of the `User` class. Users are managed by the `UserAccountManager`. Every user is uniquely identified by a `org.salespointframework.useraccount.UserAccountIdentifier`, which also serves as primary key attribute for the database.
The username of the `org.salespointframework.useraccount.UserAccount` can be retrieved by the `getUsername()` method.

**`UserAccount` can not be sub-classed.** +
**`UserAccount` are managed by `UserAccountManager`.**

**Example of working with `UserAccount` see https://github.com/st-tu-dresden/videoshop/blob/master/src/main/java/videoshop/VideoShopDataInitializer.java#L123[Videoshop @ Github].**

.Overview of UserAccount attributes
[source, java, indent=0]
----
include::{source-base}/useraccount/UserAccount.java[tags=attributes]
----
<1> username of UserAccount, required
<2> password for UserAccount, required
<3> roles for UserAccount, required

[[modules.useraccount.role]]
=== Roles
`org.salespointframework.useraccount.Role`s in conjunction with authorization tag `hasRole()` can be used to change the appearance of a View, depending on a user’s status. For example, a View for a user having an “administrator” role may display different content, for example delete buttons, than for a user not having that role. Thus, roles allow for flexibility and assist in code reuse, when designing the `View`.
`org.salespointframework.useraccount.Role` s in conjunction with authorization tag `hasRole()` can be used to change the appearance of a View, depending on a user’s status. For example, a View for a user having an “administrator” role may display different content, for example delete buttons, than for a user not having that role. Thus, roles allow for flexibility and assist in code reuse, when designing the `View`.

[[modules.useraccount.login]]
=== Login
To reduce code repetition, Salespoint {majorversion} contains code to automate the user log in. Using a Thymeleaf template, a special login form is generated, which is handled by an interceptor. The interceptor verifies the user password and associates the current session with the user using `<login>` and `<logoff>`. The session is required, because multiple users can be logged on at the same time.
To reduce code repetition, Salespoint {version} contains code to automate the user log in. Using a Thymeleaf template, a special login form is generated, which is handled by an interceptor. The interceptor verifies the user password and associates the current session with the user using `<login>` and `<logoff>`. The session is required, because multiple users can be logged on at the same time.

[[modules.useraccount.limitation]]
=== Limitation
The `org.salespointframework.useraccount.UserAccount` is limited to the given attributes and methods.
IMPORTANT: The `org.salespointframework.useraccount.UserAccount` is limited to the given attributes and methods.
Due to the fact, that Salespoint use the `SecurityContext` for authentication, the `UserAccount` cannot be extended. In the background the `org.salespointframework.useraccount.UserAccount` is converted to an instance of `org.springframework.security.core.userdetails.UserDetails`.

If these properties don’t meet all requirements, wrap the `UserAccount` in a new entity. Put all the new features in this new entity and connect this information via a `@OneToOne` relationship with the `UserAccount`. An example can be found in the Videoshop project.

.Example of a UserAccount extension
====
[source, java]
----
@Entity
Expand All @@ -214,48 +230,74 @@ public class UserAccountExtension {
}
----
====

[[modules.quantity]]
== Quantity
`Quantity` is used to represent amounts of anything. Furthermore a `Quantity` can be used to calc with (plus, minus).
But only `Quantities` with the same `Metric` can be combined or compared, so every `Quantity` has an `Metric` attribute.

And of course, every `Quantity` has an amount value, represented as a `java.math.BigDecimal`.

.Overview of Quantity attributes
[source, java, indent=0]
----
include::{source-base}/quantity/Quantity.java[tags=attributes]
----

[[modules.quantity.metric]]
=== Metric
The composite type `Metric` contains all information pertaining to the unit or metric of the represented object.
Furthermore, an object of type `Metric` has a description field, to explain the meaning of the metric in detail. For the example of a meter a possible description could be "The meter is the length of the path travelled by light in vacuum during a time interval of 1/299 792 458 of a second.".

[[modules.catalog]]
== Catalog
== Product
Salespoint {majorversion} is intended as framework for point-of-sale applications. Items for sale are called products and represented by instances of the class `Product`. To represent different kinds of products, `Product` can be sub-classed. Products are identified using a `ProductIndentifier`.

Salespoint {majorversion} is intended as framework for point-of-sale applications. Items for sale are called products and represented by instances of the class `Product`. To represent different kinds of products, `Product` can be sub-classed. Products are managed by a `Catalog` implementation (see below). Products are identified using a `ProductIndentifier`.
**`Products` are managed by a `Catalog` implementation.** +
**`Products` can be sub-classed**

The `Catalog` interface was designed to manage `Product` instances in the system. It provides functionality to add, remove, and find products. Products can be searched by their name or category. The `PersistentCatalog` is an implementation of the `Catalog` interface.
.Overview of Product attributes
[source, java, indent=0]
----
include::{source-base}/catalog/Product.java[tags=attributes]
----

=== Catalog
////
[Product]<-[<<Interface>> Catalog]
[<<Interface>> SalespointRepository]^[<<Interface>> Catalog]
////
image::catalog.png[title="Catalog"]

The `Catalog` interface was designed to manage `Product` instances in the system. It provides functionality to add, remove, and find products. Products can be searched by their name or category.

[[modules.accountancy]]
== Accountancy
The accountancy package contains functionality supporting book keeping. `AccountancyEntry` is a representation of an accounting entry. `Accountancy` aggregates ``AccountancyEntry``s. Every `AccountancyEntry` is uniquely identified by an ``AccountancyEntryIdentifier``. `AccountancyEntry` extends `AbstractEntity` and serves as persistence entity, while `PersistentAccountancy` implements `Accountancy` and provides transparent access to the JPA layer. `AccountancyEntryIdentifier` is used as primary key attribute, when entities are stored in the database.

////
[<<Interface>> Accountancy]^-.-[PersistentAccountancy]
[PersistentAccountancy]uses-.->[<<Interface>> AccountancyEntryRepository]
[AccountancyEntry|-id:AccountancyEntryIdentifier]
////
image::accountancy.png[Accountancy, title="Accountancy"]

The accountancy package contains functionality supporting book keeping. `AccountancyEntry` is a representation of an accounting entry. Every `AccountancyEntry` is uniquely identified by an `AccountancyEntryIdentifier`. `AccountancyEntryIdentifier` is used as primary key attribute, when entities are stored in the database.

By implementing and sub-classing `Accountancy`, the notion of different accounts, as known from double-entry bookkeeping, can be realised.

To create a new account, `AccountancyEntry` has to be sub-classed. Every object of such a class belongs to the same account. Accessing per-account entries is facilitated by specifiying the desired class type when calling `get()` or `find()` methods of `Accountancy`.

.Usage of Accountancy
[source, java, indent=0]
----
public class ExampleImplementation {
include::{source-base-test}/accountancy/AccountancyTests.java[tags=init]
{...}
}
----
<1> Initialization of an `Accountancy` of class `AccountancyEntry`
<2> Initialization of an `Accountancy` of class `ProductPaymentEntry`, (sub-class of `AccountancyEntry`)

[[modules.payment]]
== Payments

Expand Down Expand Up @@ -334,6 +376,12 @@ image::business-time.png[title="Business time"]

Besides the business modules, Salespoint containes a few <<glossary.spi,SPIs>> that can be used to extend the functionality of the core framework. These SPIs usually exist to make repeated use-cases easier to implement and free you from writing too much boilerplate code.

=== Salespoint-Interfaces (Salespoint-Repository)

==== Interfaces extended from `SalespointRepository`

==== Interfaces not from `SalespointRepository`

[[modules.technical-apis.data-initializer]]
=== DataInitializer

Expand Down Expand Up @@ -380,25 +428,4 @@ SPI::
== Bibliography
- [[[ddd]]] Eric Evans. Domain-Driven Design: Tackling Complexity in the Heart of Software. Prentice Hall. 2003
- [[[epam]]] Jim Arlow, Ila Neustadt. Enterprise Patterns and MDA: Building Better Software with Archetype Patterns and UML. Addison-Wesley. 2004.
- [[[di]]] Martin Fowler. Inversion of Control Containers and the Dependency Injection pattern. 2004. http://www.martinfowler.com/articles/injection.html

[appendix]
== Asciidoc template

Some random snippets to show how Asciidoc is used. For more examples see the http://asciidoctor.org/docs/user-manual[user manual].

.Example for code snippets
====
[source, java]
----
class SomeClass { }
----
====

.Example for code included from the sources
====
[source, java]
----
include::{source-base-test}/AbstractIntegrationTests.java[tags=testBase]
----
====
- [[[di]]] Martin Fowler. Inversion of Control Containers and the Dependency Injection pattern. 2004. http://www.martinfowler.com/articles/injection.html
4 changes: 3 additions & 1 deletion src/main/java/org/salespointframework/catalog/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ public class Product extends AbstractEntity<ProductIdentifier>implements Compara

private static final long serialVersionUID = 6645371648836029780L;

// tag::attributes[]
@EmbeddedId //
@AttributeOverride(name = "id", column = @Column(name = "PRODUCT_ID") ) //
private ProductIdentifier productIdentifier = new ProductIdentifier();
private String name;
private @Lob Money price;
private @ElementCollection Set<String> categories = new HashSet<String>();
private Metric metric;
// end::attributes[]

/**
* Parameterless constructor required for JPA. Do not use.
Expand Down Expand Up @@ -150,4 +152,4 @@ public int compareTo(Product other) {
public String toString() {
return name;
}
}
}
4 changes: 3 additions & 1 deletion src/main/java/org/salespointframework/quantity/Quantity.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ public class Quantity {

private static final String INCOMPATIBLE = "Quantity %s is incompatible to quantity %s!";

// tag::attributes[]
private @NonNull final BigDecimal amount;
private @NonNull final Metric metric;
// end::attributes[]

Quantity() {
this.amount = null;
Expand Down Expand Up @@ -178,4 +180,4 @@ private void assertCompatibility(Quantity quantity) {
public String toString() {
return new DecimalFormat().format(amount).concat(metric.getAbbreviation());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,23 @@ public class UserAccount extends AbstractEntity<UserAccountIdentifier> {

private static final long serialVersionUID = -795038599473743418L;

// tag::attributes[]
@EmbeddedId//
@AttributeOverride(name = "id", column = @Column(name = "USERACCOUNT_ID"))//
private UserAccountIdentifier userAccountIdentifier;
private UserAccountIdentifier userAccountIdentifier; // <1>

@Column(nullable = false)//
private Password password;
private Password password; // <2>

private String firstname;
private String lastname;
private String email;

@ElementCollection(fetch = FetchType.EAGER)//
private Set<Role> roles = new TreeSet<Role>();
private Set<Role> roles = new TreeSet<Role>(); // <3>

private boolean enabled;
// end::attributes[]

@Deprecated
protected UserAccount() {
Expand Down Expand Up @@ -164,4 +166,4 @@ public String getEmail() {
public void setEmail(String email) {
this.email = email;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
@SuppressWarnings("javadoc")
public class AccountancyTests extends AbstractIntegrationTests {

@Autowired Accountancy<AccountancyEntry> a;
@Autowired Accountancy<ProductPaymentEntry> p;
// tag::init[]
@Autowired Accountancy<AccountancyEntry> a; //<1>
@Autowired Accountancy<ProductPaymentEntry> p; //<2>
// end::init[]
@Autowired UserAccountManager userAccountManager;

private LocalDateTime from;
Expand All @@ -40,11 +42,14 @@ public void testSetup() throws Exception {
user = userAccountManager.save(user);
OrderIdentifier orderIdentifier = new Order(user).getIdentifier();

a.add(new ProductPaymentEntry(orderIdentifier, user, Money.of(1, Currencies.EURO), "Rechnung nr " + year,
Cash.CASH));
// tag::addP[]
a.add(new ProductPaymentEntry(orderIdentifier, user, Money.of(1, Currencies.EURO), "Rechnung nr " + year, Cash.CASH));
// end::addP[]
} else {
System.out.println("PersistentAccountancyEntry");
// tag::addA[]
a.add(new AccountancyEntry(Money.of(2.22, Currencies.EURO)));
// end::addA[]
}

if (year == 2002) {
Expand Down Expand Up @@ -91,4 +96,4 @@ public void selectType() {
}

}
}
}

0 comments on commit ee77933

Please sign in to comment.