100days

View the Project on GitHub

ERP in 100 Tagen

063 Templates: Tablet Kunden Adressen

alt text

062 Templates: Mobile Kunden Adressen

alt text

061 Templates: Desktop Kunden Detail

alt text

060 Templates: Tablet Kunden Detail

alt text

059 Templates: Mobile Kunden Detail

alt text

058 Templates: Desktop Kundenliste

alt text

057 Templates: Tablet Kundenliste

alt text

056 Templates: Mobile Kundenliste

alt text

055 Templates: Desktop Login

alt text

054 Templates: Tablet Login

alt text

053 Templates: Mobile Login

alt text

052 Templates: Desktop Artikeldetail History

alt text

051 Templates: Tablet Artikeldetail History

alt text

050 Templates: Mobile Artikeldetail History

alt text

049 Templates: Desktop Artikeldetail Preise

alt text

048 Templates: Tablet Artikeldetail Preise

alt text

047 Templates: Mobile Artikeldetail Preise

alt text

046 Templates: Desktop Artikeldetail

alt text

045 Templates: Tablet (Quer) Artikeldetail

alt text

044 Templates: Mobile Artikeldetail

(Leider wollte mein Chrome nicht so wie ich wollte…)

alt text

043 Templates: Desktop Dashboard

alt text

042 Templates: Tablet Dashboard

alt text

041 Templates: Mobile Dashboard

alt text

040 Templates: Mobile Menu

alt text

039 CSS Layout Grid

$num-cols: 12;

html {
  font-size: 2vw;
}

.container {
  margin: 0 auto;
  max-width: 1280px;
  width: 90%;
}

.row {
  margin-bottom: 20px;

  &:after {
    content: "";
    display: block;
    clear: both;
  }

  .col {
    float: left;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;

    $i: 1;
    @while($i <= $num-cols) {
      &.s#{$i} {
        width: percentage($i / $num-cols);
      }
      $i: $i + 1;
    }

    @media only screen and (min-width: 38em) {
      $i: 1;
      @while($i <= $num-cols) {
        &.m#{$i} {
          width: percentage($i / $num-cols);
        }
        $i: $i + 1;
      }
    }

    @media only screen and (min-width: 60em) {
      $i: 1;
      @while($i <= $num-cols) {
        &.l#{$i} {
          width: percentage($i / $num-cols);
        }
        $i: $i + 1;
      }
    }
  }
}

038 CSS Layout Grid

.col {
    float: left;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;

    $i: 1;
    @while($i <= $num-cols) {
      &.s#{$i} {
        width: percentage($i / $num-cols);
      }
      $i: $i + 1;
    }

    @media only screen and (min-width: 38em) {
      $i: 1;
      @while($i <= $num-cols) {
        &.m#{$i} {
          width: percentage($i / $num-cols);
        }
        $i: $i + 1;
      }
    }
  }

037 CSS Layout Grid

.row .col.s1 {
    width: 8.33333%;
}

.row .col.s2 {
    width: 16.66667%;
}

.row .col.s3 {
    width: 25%;
}

.row .col.s4 {
    width: 33.33333%;
}

.row .col.s5 {
    width: 41.66667%;
}

.row .col.s6 {
    width: 50%;
}

.row .col.s7 {
    width: 58.33333%;
}

.row .col.s8 {
    width: 66.66667%;
}

.row .col.s9 {
    width: 75%;
}

.row .col.s10 {
    width: 83.33333%;
}

.row .col.s11 {
    width: 91.66667%;
}

.row .col.s12 {
    width: 100%;
}
.col {
    float: left;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;

    $i: 1;
    @while($i <= $num-cols) {
      &.s#{$i} {
        width: percentage($i / $num-cols);
      }
      $i: $i + 1;
    }
  }

036 CSS Layout Grid

.container {
    margin: 0 auto;
    max-width: 1280px;
    width: 90%;
}

.row {
    margin-bottom: 20px;
}

.row:after {
    content: "";
    display: block;
    clear: both;
}

.row .col {
    float: left;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}

.row .col.s1 {
    width: 8.3333333333%;
    left: auto;
    right: auto;
}

035 Programmierung: Redux Reducer - Artikel

const initialState = {
    fetching: false,
    fetched: false,
    articles: [],
    error: null
};

export default function (state = initialState, action) {
    switch (action.type) {
        case "FETCH_ARTICLES":
            return {...state, fetching: true};
            break;
        case "FETCH_ARTICLES_FULFILLED":
            return {...state, fetching: false, fetched: true, articles: action.payload.data};
            break;
        case "FETCH_ARTICLES_REJECTED":
            return {...state, fetching: false, error: action.payload};
        default:
            return state;
            break;
    }
}

034 Programmierung: Redux Schnittstellenzugriff - Artikel

const articleGroupEpic = action$ =>
    action$.ofType("FETCH_ARTICLE_GROUPS")
        .mergeMap(action =>
            ajax.getJSON("http://angular-erp.dev/api/article_groups")
                .map(response => ({type: "FETCH_ARTICLE_GROUPS_FULFILLED", payload: response}))
                .catch(error => Observable.of({
                    type: "FETCH_ARTICLE_GROUPS_REJECTED",
                    payload: error.xhr.response,
                    error: true
                })));

033 Design: Einstellungen

alt text

032 Design: Rechnung - Historie

alt text

031 Design: Rechnung - Belegdaten

alt text

030 Design: Rechnung - Artikel

alt text

029 Design: Rechnung (nicht final)

alt text

028 Design: Kunden Detail - Historie

alt text

027 Design: Kunden Detail - Adresse

alt text

026 Design: Kunden Detail - Neue Adresse

alt text

025 Design: Kunden Detail

alt text

024 Design: Artikel Detail Historie

alt text

023 Design: Artikel Detail Preis

alt text

022 Datenbankschema: Logs

alt text

021 Design: Belegauswertung

alt text

020 Design: Login

alt text

019 Design: Dashboard

alt text

018 Design: Artikelgruppe anlegen

alt text

017 Artikelgruppenübersicht - Desktop

alt text

016 Programmierung: API

class CustomersController extends Controller
    {

        use Helpers;

        public function index()
        {
            $taxRates = Customer::all();

            return $this->response->collection($taxRates, new CustomerTransformer());
        }

        public function add(CustomerRequest $request)
        {
            if(Customer::create($request->all())) {
                if(AddressSet::create($request->all())) {
                    return $this->response->created();
                }
            }

            return $this->response->errorBadRequest();
        }

        public function get($id)
        {
            $article = Customer::find($id);
            if ($article) {
                return $this->response->item($article, new CustomerTransformer());
            }

            return $this->response->errorNotFound();
        }

    }

015 Programmierung: API

class TaxRatesController extends Controller
    {
        
        use Helpers;

        public function index()
        {
            $taxRates = TaxRate::all();

            return $this->response->collection($taxRates, new TaxRateTransformer());
        }

        public function add(TaxRateRequest $request)
        {
            if(TaxRate::create($request->all())) {
                return $this->response->created();
            }

            return $this->response->errorBadRequest();
        }

        public function get($id)
        {
            $article = TaxRate::find($id);
            if ($article) {
                return $this->response->item($article, new TaxRateTransformer());
            }

            return $this->response->errorNotFound();
        }
        
    }

014 Programmierung: API

public function add(ArticleRequest $request)
    {
        if(Article::create($request->all())) {
            return $this->response->created();
        }

        return $this->response->errorBadRequest();
    }

public function get($id)
    {
        $article = Article::find($id);
        if ($article) {
            return $this->response->item($article, new ArticlesTransformer());
        }

        return $this->response->errorNotFound();
    }

013 Artikelübersicht - Desktop

alt text

012 Artikelübersicht - Handy

alt text

011 Programmierung

Die ersten API Aufrufe aus dem Programm.

alt text

010 Programmierung: API

Ein weiterer Teil der API.

    class ArticleGroupsController extends Controller
    {

        use Helpers;

        public function index()
        {
            $articleGroups = ArticleGroup::all();

            return $this->response->collection($articleGroups, new ArticleGroupsTransformer());
        }

        public function add(ArticleGroupRequest $request)
        {
            if (ArticleGroup::create($request->all())) {
                return $this->response->created();
            }

            return $this->response->errorBadRequest();
        }

        public function get($id)
        {
            $fruit = ArticleGroup::find($id);
            if ($fruit) {
                return $this->response->item($fruit, new ArticleGroupsTransformer());
            }

            return $this->response->errorNotFound();
        }

    }

009 Programmierung: API

Heute habe ich mich mit der User-Authentifizierung beschäftigt. Mein Ziel ist es den User über JSON Web Tokens mit der Api kommunizieren zu lassen. Nach dem Login wird für den User ein JSON Web Token erzeugt. Diesen schickt er bei jeder Anfrage an die Api mit. Diese kann dann überprüfen, ob der Token noch gültig ist und um welchen User es sich handelt.

        /**
         *  API Login, on success return JWT Auth token
         *
         * @param \Illuminate\Http\Request $request
         *
         * @return \Illuminate\Http\JsonResponse
         */
        public function authenticate(Request $request)
        {
            // grab credentials from the request
            $credentials = array("email" => $request->json("email"), "password" => $request->json("password"));


            try {
                // attempt to verify the credentials and create a token for the user
                if (!$token = JWTAuth::attempt($credentials)) {
                    return response()->json(['error' => 'invalid_credentials'], 401);
                }
            } catch (JWTException $e) {
                // something went wrong whilst attempting to encode the token
                return response()->json(['error' => 'could_not_create_token'], 500);
            }

            // all good so return the token
            return response()->json(compact('token'));
        }

008 Programmierung: API

Heute habe ich die ersten Funktionen der Schnittstelle programmiert, die mir später die Daten an das Frontend liefert. Hier ein paar Eindrücke.

public function index()
    {
        $articles = Article::all();

        return $this->response->collection($articles, new ArticlesTransformer(), [], function ($resource, $fractal) {
            $fractal->parseIncludes("article_group");
        });
    }
class ArticlesTransformer extends TransformerAbstract
    {

        protected $availableIncludes = ["article_group"];

        public function transform(Article $article)
        {
            return [
                "id" => (int) $article->id,
                "sku" => $article->sku,
                "name" => $article->name,
                "description" => $article->description
            ];
        }

        public function includeArticleGroup(Article $article)
        {
            $articleGroup = $article->article_group;

            return $this->item($articleGroup, new ArticleGroupsTransformer());
        }
    }

007 Umsetzung: Navigationsleiste

alt text

006 Design: Artikeldetail

alt text

005 Design: Artikelübersicht

alt text

004 Datenbankschema: Rechnungen Teil 2

Das Datenbankschema ist vorerst fertig. Als nächstes geht es an die Erstellung der einzelnen Views.

alt text

003 Datenbankschema: Rechnungen Teil 1

alt text

002 Datenbankschema: Kundentabelle

Heute habe ich mich mit dem Anlegen der Kundentabelle, sowie andere zugehörige Tabellen, wie zum Beispiel zugehörige Adressen.

alt text

001 Datenbankschema: Artikel

alt text