392 lines
9.3 KiB
Go
392 lines
9.3 KiB
Go
package paxan
|
|
|
|
import (
|
|
"encoding/csv"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"net/http/cookiejar"
|
|
"net/url"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/PuerkitoBio/goquery"
|
|
"golang.org/x/text/encoding/charmap"
|
|
)
|
|
|
|
type paxanWebOrder struct {
|
|
InvoiceNumber int
|
|
Type string
|
|
Date string
|
|
}
|
|
|
|
type paxanWebOrderEntry struct {
|
|
Position string
|
|
ArticleNumber int
|
|
Description string
|
|
ProductLink string
|
|
Amount string
|
|
Price string
|
|
Total string
|
|
Amount2 string
|
|
Price2 string
|
|
Total2 string
|
|
}
|
|
|
|
// SpricelistEntry - One entry in the spricelist
|
|
type SpricelistEntry struct {
|
|
Sortiment string
|
|
Warengruppe string
|
|
Untergruppe string
|
|
Artnr int
|
|
Itemname1 string
|
|
Itemname2 string
|
|
Hersteller string
|
|
Qualitaet string
|
|
Herkunft string
|
|
Einheit string
|
|
Aktion bool
|
|
Menge1 float64
|
|
Einzelpreis1 float64
|
|
Vpepreis1 float64
|
|
Menge2 string
|
|
Einzelpreis2 string
|
|
Vpepreis2 string
|
|
Menge3 string
|
|
Einzelpreis3 string
|
|
Vpepreis3 string
|
|
Menge4 string
|
|
Einzelpreis4 string
|
|
Vpepreis4 string
|
|
Empfvk float64
|
|
Mwst float64
|
|
Ean string
|
|
Glutenfrei bool
|
|
Laktosefrei bool
|
|
Vegan bool
|
|
Regional bool
|
|
Fairtrade bool
|
|
}
|
|
|
|
func convertStringToBool(value string) bool {
|
|
if value == "X" {
|
|
return true
|
|
}
|
|
if value == "A" {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func convertStringToFloat(value string) float64 {
|
|
value = strings.Replace(value, " €", "", -1)
|
|
value = strings.Replace(value, ",", ".", -1)
|
|
valueFloat, _ := strconv.ParseFloat(value, 46)
|
|
return valueFloat
|
|
}
|
|
|
|
func convertStringToInt(value string) int {
|
|
valueInt, _ := strconv.Atoi(value)
|
|
return valueInt
|
|
}
|
|
|
|
func convertStringToTime(value string) time.Time {
|
|
time, err := time.Parse("02.01.06", value)
|
|
if err != nil {
|
|
log.Fatalln(err)
|
|
}
|
|
return time
|
|
}
|
|
|
|
func downloadFile(filepath string, resp *http.Response) error {
|
|
// Create the file
|
|
file, err := os.Create(filepath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
// Write the body to file
|
|
_, err = io.Copy(file, resp.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// NewClient - Login
|
|
func NewClient(user string, password string) (*http.Client, error) {
|
|
// New http client with cookie
|
|
cookieJar, _ := cookiejar.New(nil)
|
|
client := &http.Client{
|
|
Jar: cookieJar,
|
|
}
|
|
|
|
loginvalues := make(url.Values)
|
|
loginvalues.Set("performAction", "processLogin")
|
|
loginvalues.Set("personlogin", user)
|
|
loginvalues.Set("personpwd", password)
|
|
loginvalues.Set("firma", "paxan")
|
|
_, err := client.PostForm("https://www.hakopaxan-shop.de/html/login.html", loginvalues)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return client, nil
|
|
}
|
|
|
|
// CloseClient - Logout
|
|
func CloseClient(client *http.Client) error {
|
|
// Logout
|
|
_, err := client.Get("https://www.hakopaxan-shop.de/html/logout-performAction-processLogout.html")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DownloadPricelists - Download both price lists
|
|
func DownloadPricelists(client *http.Client) error {
|
|
// Download preisliste
|
|
r, err := client.Get("https://www.hakopaxan-shop.de/csv/preisliste.csv")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
downloadFile(("preisliste-" + time.Now().Format("20060102150405") + ".csv"), r)
|
|
|
|
// Download spreisliste
|
|
r, err = client.Get("https://www.hakopaxan-shop.de/csv/spreisliste.csv")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
downloadFile(("spreisliste-" + time.Now().Format("20060102150405") + ".csv"), r)
|
|
|
|
return nil
|
|
}
|
|
|
|
// RetrievePricelist - Downloads and converts pricelist into an array
|
|
func RetrievePricelist(client *http.Client) ([]SpricelistEntry, error) {
|
|
// Download spreisliste
|
|
resp, err := client.Get("https://www.hakopaxan-shop.de/csv/spreisliste.csv")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
dr := charmap.ISO8859_1.NewDecoder().Reader(resp.Body)
|
|
|
|
r := csv.NewReader(dr)
|
|
r.Comma = ';'
|
|
records, err := r.ReadAll()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
var priceList []SpricelistEntry
|
|
|
|
for i, line := range records {
|
|
if i == 0 {
|
|
continue
|
|
}
|
|
var priceListEntry SpricelistEntry
|
|
|
|
priceListEntry.Sortiment = line[0]
|
|
priceListEntry.Warengruppe = line[1]
|
|
priceListEntry.Untergruppe = line[2]
|
|
priceListEntry.Artnr = convertStringToInt(line[3])
|
|
priceListEntry.Itemname1 = line[4]
|
|
priceListEntry.Itemname2 = line[5]
|
|
priceListEntry.Hersteller = line[6]
|
|
priceListEntry.Qualitaet = line[7]
|
|
priceListEntry.Herkunft = line[8]
|
|
priceListEntry.Einheit = line[9]
|
|
priceListEntry.Aktion = convertStringToBool(line[10])
|
|
priceListEntry.Menge1 = convertStringToFloat(line[11])
|
|
priceListEntry.Einzelpreis1 = convertStringToFloat(line[12])
|
|
priceListEntry.Vpepreis1 = convertStringToFloat(line[13])
|
|
priceListEntry.Menge2 = line[14]
|
|
priceListEntry.Einzelpreis2 = line[15]
|
|
priceListEntry.Vpepreis2 = line[16]
|
|
priceListEntry.Menge3 = line[17]
|
|
priceListEntry.Einzelpreis3 = line[18]
|
|
priceListEntry.Vpepreis3 = line[19]
|
|
priceListEntry.Menge4 = line[20]
|
|
priceListEntry.Einzelpreis4 = line[21]
|
|
priceListEntry.Vpepreis4 = line[22]
|
|
priceListEntry.Empfvk = convertStringToFloat(line[23])
|
|
priceListEntry.Mwst = convertStringToFloat(line[24])
|
|
priceListEntry.Ean = line[25]
|
|
priceListEntry.Glutenfrei = convertStringToBool(line[26])
|
|
priceListEntry.Laktosefrei = convertStringToBool(line[27])
|
|
priceListEntry.Vegan = convertStringToBool(line[28])
|
|
priceListEntry.Regional = convertStringToBool(line[29])
|
|
priceListEntry.Fairtrade = convertStringToBool(line[30])
|
|
|
|
priceList = append(priceList, priceListEntry)
|
|
}
|
|
|
|
return priceList, nil
|
|
|
|
}
|
|
|
|
func paxanGetOrders(client *http.Client) ([]paxanWebOrder, error) {
|
|
var list []paxanWebOrder
|
|
kvs := make(map[string]string)
|
|
|
|
r, err := client.Get("https://www.hakopaxan-shop.de/html/customerDocumentList.html?customerDocumentListId=invoice&requestedPeriod=365")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
doc, err := goquery.NewDocumentFromReader(io.Reader(r.Body))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var headline []string
|
|
// Find the table header
|
|
doc.Find(".tableHeader").Each(func(i int, s *goquery.Selection) {
|
|
s.Find(".tableCell").Each(func(i int, s *goquery.Selection) {
|
|
title := s.Contents().Text()
|
|
title = strings.Replace(title, "\n", "", -1)
|
|
title = strings.TrimSpace(title)
|
|
|
|
headline = append(headline, title)
|
|
})
|
|
})
|
|
|
|
// Find the table items
|
|
doc.Find(".tableRowGroup").Each(func(i int, s *goquery.Selection) {
|
|
s.Find(".tableCell").Each(func(j int, s *goquery.Selection) {
|
|
title := "undefined"
|
|
if j < len(headline) {
|
|
title = headline[j]
|
|
}
|
|
|
|
text := s.Contents().Text()
|
|
text = strings.Replace(text, "\n", "", -1)
|
|
text = strings.Split(text, ":")[1]
|
|
text = strings.TrimSpace(text)
|
|
kvs[title] = text
|
|
//fmt.Printf("%s - %s\n", title, text)
|
|
})
|
|
//fmt.Println(kvs)
|
|
|
|
num, _ := strconv.Atoi(kvs["Beleg-Nr."])
|
|
n := paxanWebOrder{InvoiceNumber: num, Type: kvs["Belegart"], Date: kvs["Datum"]}
|
|
list = append(list, n)
|
|
})
|
|
|
|
return list, nil
|
|
}
|
|
|
|
func paxanGetOrderDetails(client *http.Client, orderNumber int) ([]paxanWebOrderEntry, error) {
|
|
var list []paxanWebOrderEntry
|
|
|
|
url := "https://www.hakopaxan-shop.de/html/customerDocument-customerDocumentId-" + strconv.Itoa(orderNumber) + "-customerDocumentListId-invoice-requestedPeriod-365.html"
|
|
r, err := client.Get(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
doc, err := goquery.NewDocumentFromReader(io.Reader(r.Body))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Go through table row by row
|
|
doc.Find(".tableRowGroup").Each(func(i int, s *goquery.Selection) {
|
|
var row []string
|
|
s.Find(".tableCell").Each(func(j int, s *goquery.Selection) {
|
|
text := s.Contents().Text()
|
|
// Column 3 contains some more info
|
|
if j == 2 {
|
|
text = s.Find(".lineItemName").Text()
|
|
// Search for the link to the product page
|
|
linkTag := s.Find("a")
|
|
link, _ := linkTag.Attr("href")
|
|
row = append(row, link)
|
|
}
|
|
|
|
text = strings.Replace(text, "\n", "", -1)
|
|
text = strings.TrimSpace(text)
|
|
row = append(row, text)
|
|
|
|
})
|
|
|
|
num, _ := strconv.Atoi(row[1])
|
|
n := paxanWebOrderEntry{Position: row[0],
|
|
ArticleNumber: num,
|
|
Description: row[3],
|
|
ProductLink: row[2],
|
|
Amount: row[4],
|
|
Price: row[5],
|
|
Total: row[6],
|
|
Amount2: row[7],
|
|
Price2: row[8],
|
|
Total2: row[9]}
|
|
list = append(list, n)
|
|
})
|
|
|
|
return list, nil
|
|
}
|
|
|
|
// ExportNewOrders - Export new orders into orders.csv
|
|
func ExportNewOrders(client *http.Client, lastOrder int) error {
|
|
f, err := os.OpenFile("orders.csv", os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0600)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
orders, err := paxanGetOrders(client)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
i, j := 0, 0
|
|
for _, order := range orders {
|
|
if order.InvoiceNumber <= lastOrder {
|
|
continue
|
|
}
|
|
|
|
orderDetails, err := paxanGetOrderDetails(client, order.InvoiceNumber)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, orderDetail := range orderDetails {
|
|
text := strconv.Itoa(order.InvoiceNumber) + ";" +
|
|
order.Type + ";" +
|
|
order.Date + ";" +
|
|
|
|
orderDetail.Position + ";" +
|
|
strconv.Itoa(orderDetail.ArticleNumber) + ";" +
|
|
orderDetail.Description + ";" +
|
|
orderDetail.ProductLink + ";" +
|
|
orderDetail.Amount + ";" +
|
|
orderDetail.Price + ";" +
|
|
orderDetail.Total + ";" +
|
|
orderDetail.Amount2 + ";" +
|
|
orderDetail.Price2 + ";" +
|
|
orderDetail.Total2 + "\n"
|
|
|
|
_, err = f.WriteString(text)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
j++
|
|
}
|
|
|
|
i++
|
|
}
|
|
|
|
log.Printf("Added %d order(s) with %d article(s)", i, j)
|
|
|
|
return nil
|
|
}
|