Skip to content

Commit f2f77d1

Browse files
Release-0.5 (#299)
* Search Criteria improved with sigil * Added payment types, fixed docs * Fix search criteria for in and not in
1 parent f1744c7 commit f2f77d1

File tree

8 files changed

+294
-31
lines changed

8 files changed

+294
-31
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## 0.5.0
4+
5+
* SearchCriteria changed to sigil ~f with separations for reduced name lengths (old functionality is still there for now)
6+
* Payment Types added
7+
38
## 0.4.2
49

510
* Added Github Action to automatically publish a package version

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ by adding `bexio_api_client` to your list of dependencies in `mix.exs`:
1111
```elixir
1212
def deps do
1313
[
14-
{:bexio_api_client, "~> 0.4.3"}
14+
{:bexio_api_client, "~> 0.5.0"}
1515
]
1616
end
1717
```

lib/bexio_api_client/others.ex

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -902,4 +902,45 @@ defmodule BexioApiClient.Others do
902902
&success_response/2
903903
)
904904
end
905+
906+
@doc """
907+
Fetch a list of payment types.
908+
"""
909+
@spec fetch_payment_types(
910+
req :: Req.Request.t(),
911+
opts :: [GlobalArguments.offset_without_order_by_arg()]
912+
) :: {:ok, map()} | api_error_type()
913+
def fetch_payment_types(req, opts \\ []) do
914+
bexio_body_handling(
915+
fn ->
916+
Req.get(req, url: "/2.0/payment_type", params: opts_to_query(opts))
917+
end,
918+
&body_to_map/2
919+
)
920+
end
921+
922+
@doc """
923+
Search a payment type
924+
925+
Following fields are supported:
926+
927+
* `name`
928+
"""
929+
@spec search_payment_types(
930+
req :: Req.Request.t(),
931+
criteria :: list(SearchCriteria.t()),
932+
opts :: [GlobalArguments.offset_arg()]
933+
) :: {:ok, map()} | api_error_type()
934+
def search_payment_types(req, criteria, opts \\ []) do
935+
bexio_body_handling(
936+
fn ->
937+
Req.post(req,
938+
url: "/2.0/payment_type/search",
939+
json: criteria,
940+
params: opts_to_query(opts)
941+
)
942+
end,
943+
&body_to_map/2
944+
)
945+
end
905946
end

lib/bexio_api_client/search_criteria.ex

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ defmodule BexioApiClient.SearchCriteria do
4747
@derive Jason.Encoder
4848
defstruct [:field, :criteria, :value]
4949

50+
@regex ~r/^(?<field>\S+)\s*(?<operator>!=|=|<=|<|>=|>|in|not in|like|not like|is nil|is not nil)\s*(?<value>.*)$/
51+
5052
defp new(field, criteria, value) do
5153
%__MODULE__{
5254
field: field,
@@ -55,6 +57,43 @@ defmodule BexioApiClient.SearchCriteria do
5557
}
5658
end
5759

60+
@spec sigil_f(String.t(), Keyword.t()) :: t()
61+
def sigil_f(field, opts)
62+
63+
def sigil_f(expression, _opts) do
64+
case Regex.run(@regex, expression, capture: :all_but_first) do
65+
nil -> raise ArgumentError, "Invalid search criteria: #{expression}"
66+
[field, operator, value] -> handle(field, operator, value)
67+
end
68+
end
69+
70+
defp handle(field, operator, value) when is_binary(field),
71+
do: handle(String.to_existing_atom(field), operator, value)
72+
73+
defp handle(field, "=", value) when is_atom(field), do: equal(field, value)
74+
defp handle(field, "!=", value) when is_atom(field), do: not_equal(field, value)
75+
defp handle(field, "<", value) when is_atom(field), do: less_than(field, value)
76+
defp handle(field, "<=", value) when is_atom(field), do: less_equal(field, value)
77+
defp handle(field, ">", value) when is_atom(field), do: greater_than(field, value)
78+
defp handle(field, ">=", value) when is_atom(field), do: greater_equal(field, value)
79+
defp handle(field, "like", value) when is_atom(field), do: like(field, value)
80+
defp handle(field, "not like", value) when is_atom(field), do: not_like(field, value)
81+
defp handle(field, "is nil", _value) when is_atom(field), do: nil?(field)
82+
defp handle(field, "is not nil", _value) when is_atom(field), do: not_nil?(field)
83+
defp handle(field, "in", value) when is_atom(field), do: part_of(field, listify(value))
84+
defp handle(field, "not in", value) when is_atom(field), do: not_part_of(field, listify(value))
85+
86+
defp handle(field, operator, value),
87+
do:
88+
raise(ArgumentError, "Invalid operator: #{operator} for field #{field} and value #{value}")
89+
90+
defp listify(value) do
91+
case ~r/^\[(?<value>.*)\]$/ |> Regex.named_captures(value) do
92+
%{"value" => value} -> String.split(value, ",")
93+
nil -> [value]
94+
end
95+
end
96+
5897
@doc "Creates a = search criteria"
5998
@spec equal(atom(), any()) :: t()
6099
def equal(field, value), do: new(field, :=, value)

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule BexioApiClient.MixProject do
44
def project do
55
[
66
app: :bexio_api_client,
7-
version: "0.4.3",
7+
version: "0.5.0",
88
elixir: "~> 1.14",
99
start_permanent: Mix.env() == :prod,
1010
deps: deps(),

test/bexio_api_client/others_test.exs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,4 +1558,63 @@ defmodule BexioApiClient.OthersTest do
15581558
assert result == true
15591559
end
15601560
end
1561+
1562+
describe "fetching a list of payment types" do
1563+
setup do
1564+
mock_request(fn
1565+
%{
1566+
method: "GET",
1567+
request_path: "/2.0/payment_type"
1568+
} = conn ->
1569+
json(conn, [
1570+
%{
1571+
"id" => 1,
1572+
"name" => "Cash"
1573+
}
1574+
])
1575+
end)
1576+
1577+
:ok
1578+
end
1579+
1580+
test "lists valid results" do
1581+
client = BexioApiClient.new("123")
1582+
1583+
assert {:ok, result} = BexioApiClient.Others.fetch_payment_types(client)
1584+
1585+
assert Enum.count(result) == 1
1586+
assert result[1] == "Cash"
1587+
end
1588+
end
1589+
1590+
describe "searching payment types" do
1591+
setup do
1592+
mock_request(fn
1593+
%{
1594+
method: "POST",
1595+
request_path: "/2.0/payment_type/search"
1596+
} = conn ->
1597+
json(conn, [
1598+
%{
1599+
"id" => 1,
1600+
"name" => "Cash"
1601+
}
1602+
])
1603+
end)
1604+
1605+
:ok
1606+
end
1607+
1608+
test "lists found results" do
1609+
client = BexioApiClient.new("123")
1610+
1611+
assert {:ok, result} =
1612+
BexioApiClient.Others.search_payment_types(client, [
1613+
SearchCriteria.equal(:name, "Cash")
1614+
])
1615+
1616+
assert Enum.count(result) == 1
1617+
assert result[1] == "Cash"
1618+
end
1619+
end
15611620
end

test/bexio_api_client/sales_order_management_test.exs

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2166,35 +2166,36 @@ defmodule BexioApiClient.SalesOrderManagementTest do
21662166

21672167
describe "fetching a list of document settings" do
21682168
setup do
2169-
json = Jason.decode! """
2170-
[
2171-
{
2172-
"id": 1,
2173-
"text": "Quote",
2174-
"kb_item_class": "KbOffer",
2175-
"enumeration_format": "AN-%nummer%",
2176-
"use_automatic_enumeration": true,
2177-
"use_yearly_enumeration": false,
2178-
"next_nr": 1,
2179-
"nr_min_length": 5,
2180-
"default_time_period_in_days": 14,
2181-
"default_logopaper_id": 1,
2182-
"default_language_id": 1,
2183-
"default_client_bank_account_new_id": 1,
2184-
"default_currency_id": 1,
2185-
"default_mwst_type": 0,
2186-
"default_mwst_is_net": true,
2187-
"default_nb_decimals_amount": 2,
2188-
"default_nb_decimals_price": 2,
2189-
"default_show_position_taxes": false,
2190-
"default_title": "Angebot",
2191-
"default_show_esr_on_same_page": false,
2192-
"default_payment_type_id": 1,
2193-
"kb_terms_of_payment_template_id": 1,
2194-
"default_show_total": true
2195-
}
2196-
]
2197-
"""
2169+
json =
2170+
Jason.decode!("""
2171+
[
2172+
{
2173+
"id": 1,
2174+
"text": "Quote",
2175+
"kb_item_class": "KbOffer",
2176+
"enumeration_format": "AN-%nummer%",
2177+
"use_automatic_enumeration": true,
2178+
"use_yearly_enumeration": false,
2179+
"next_nr": 1,
2180+
"nr_min_length": 5,
2181+
"default_time_period_in_days": 14,
2182+
"default_logopaper_id": 1,
2183+
"default_language_id": 1,
2184+
"default_client_bank_account_new_id": 1,
2185+
"default_currency_id": 1,
2186+
"default_mwst_type": 0,
2187+
"default_mwst_is_net": true,
2188+
"default_nb_decimals_amount": 2,
2189+
"default_nb_decimals_price": 2,
2190+
"default_show_position_taxes": false,
2191+
"default_title": "Angebot",
2192+
"default_show_esr_on_same_page": false,
2193+
"default_payment_type_id": 1,
2194+
"kb_terms_of_payment_template_id": 1,
2195+
"default_show_total": true
2196+
}
2197+
]
2198+
""")
21982199

21992200
mock_request(fn
22002201
%{method: "GET", request_path: "/2.0/kb_item_setting"} = conn ->

test/bexio_api_client/search_criteria_test.exs

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,122 @@ defmodule BexioApiClient.SearchCriteriaTest do
101101
assert sc.value == nil
102102
end
103103
end
104+
105+
describe "sigils " do
106+
setup do
107+
%{name: "fred"}
108+
end
109+
110+
test "equal will generate search criteria" do
111+
sc = ~f(name = fred)
112+
113+
assert sc.field == :name
114+
assert sc.criteria == :=
115+
assert sc.value == "fred"
116+
end
117+
118+
test "not_equal will generate search criteria" do
119+
sc = ~f(name != fred)
120+
121+
assert sc.field == :name
122+
assert sc.criteria == :!=
123+
assert sc.value == "fred"
124+
end
125+
126+
test "greater_than will generate search criteria" do
127+
sc = ~f(name > fred)
128+
129+
assert sc.field == :name
130+
assert sc.criteria == :>
131+
assert sc.value == "fred"
132+
end
133+
134+
test "less_than will generate search criteria" do
135+
sc = ~f(name < fred)
136+
137+
assert sc.field == :name
138+
assert sc.criteria == :<
139+
assert sc.value == "fred"
140+
end
141+
142+
test "greater_equal will generate search criteria" do
143+
sc = ~f(name >= fred)
144+
145+
assert sc.field == :name
146+
assert sc.criteria == :>=
147+
assert sc.value == "fred"
148+
end
149+
150+
test "less_equal will generate search criteria" do
151+
sc = ~f(name <= fred)
152+
153+
assert sc.field == :name
154+
assert sc.criteria == :<=
155+
assert sc.value == "fred"
156+
end
157+
158+
test "like will generate search criteria" do
159+
sc = ~f(name like fred)
160+
161+
assert sc.field == :name
162+
assert sc.criteria == :like
163+
assert sc.value == "fred"
164+
end
165+
166+
test "not_like will generate search criteria" do
167+
sc = ~f(name not like fred)
168+
169+
assert sc.field == :name
170+
assert sc.criteria == :not_like
171+
assert sc.value == "fred"
172+
end
173+
174+
test "part_of will generate search criteria" do
175+
sc = ~f(name in fred,me)
176+
177+
assert sc.field == :name
178+
assert sc.criteria == :in
179+
assert sc.value == ["fred,me"]
180+
end
181+
182+
test "part_of will generate search criteria in list" do
183+
sc = ~f(name in [fred,me])
184+
185+
assert sc.field == :name
186+
assert sc.criteria == :in
187+
assert sc.value == ["fred", "me"]
188+
end
189+
190+
test "not_part_of will generate search criteria" do
191+
sc = ~f(name not in fred,me)
192+
193+
assert sc.field == :name
194+
assert sc.criteria == :not_in
195+
assert sc.value == ["fred,me"]
196+
end
197+
198+
test "not_part_of will generate search criteria in list" do
199+
sc = ~f(name not in [fred,me])
200+
201+
assert sc.field == :name
202+
assert sc.criteria == :not_in
203+
assert sc.value == ["fred", "me"]
204+
end
205+
206+
test "nil? will generate search criteria" do
207+
sc = ~f(name is nil)
208+
209+
assert sc.field == :name
210+
assert sc.criteria == :is_null
211+
assert sc.value == nil
212+
end
213+
214+
test "not_nil? will generate search criteria" do
215+
sc = ~f(name is not nil)
216+
217+
assert sc.field == :name
218+
assert sc.criteria == :not_null
219+
assert sc.value == nil
220+
end
221+
end
104222
end

0 commit comments

Comments
 (0)