001/*
002 *   Copyright 2024 Vonage
003 *
004 *   Licensed under the Apache License, Version 2.0 (the "License");
005 *   you may not use this file except in compliance with the License.
006 *   You may obtain a copy of the License at
007 *
008 *        http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *   Unless required by applicable law or agreed to in writing, software
011 *   distributed under the License is distributed on an "AS IS" BASIS,
012 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *   See the License for the specific language governing permissions and
014 *   limitations under the License.
015 */
016package com.vonage.client.subaccounts;
017
018import com.vonage.client.DynamicEndpoint;
019import com.vonage.client.RestEndpoint;
020import com.vonage.client.HttpWrapper;
021import com.vonage.client.auth.ApiKeyHeaderAuthMethod;
022import com.vonage.client.common.HttpMethod;
023import java.util.List;
024import java.util.Objects;
025import java.util.function.Function;
026
027public class SubaccountsClient {
028        final RestEndpoint<CreateSubaccountRequest, Account> createSubaccount;
029        final RestEndpoint<UpdateSubaccountRequest, Account> updateSubaccount;
030        final RestEndpoint<Void, ListSubaccountsResponse> listSubaccounts;
031        final RestEndpoint<String, Account> getSubaccount;
032        final RestEndpoint<ListTransfersFilter, ListTransfersResponseWrapper> listBalanceTransfers, listCreditTransfers;
033        final RestEndpoint<MoneyTransfer, MoneyTransfer> transferBalance, transferCredit;
034        final RestEndpoint<NumberTransfer, NumberTransfer> transferNumber;
035
036        /**
037         * Constructor.
038         *
039         * @param wrapper (REQUIRED) shared HTTP wrapper object used for making REST calls.
040         */
041        public SubaccountsClient(HttpWrapper wrapper) {
042
043                @SuppressWarnings("unchecked")
044                final class Endpoint<T, R> extends DynamicEndpoint<T, R> {
045                        Endpoint(Function<T, String> pathGetter, HttpMethod method, R... type) {
046                                super(DynamicEndpoint.<T, R> builder(type)
047                                                .responseExceptionType(SubaccountsResponseException.class)
048                                                .wrapper(wrapper).requestMethod(method).authMethod(ApiKeyHeaderAuthMethod.class)
049                                                .pathGetter((de, req) -> {
050                                                        final String apiKey = de.getHttpWrapper().getApiKey();
051                                                        if (apiKey == null) {
052                                                                throw new IllegalStateException("Primary account API key is unavailable.");
053                                                        }
054                                                        if (req instanceof CreateSubaccountRequest) {
055                                                                CreateSubaccountRequest csr = (CreateSubaccountRequest) req;
056                                                                csr.primaryAccountApiKey = apiKey;
057                                                        }
058                                                        return String.format(
059                                                                        de.getHttpWrapper().getHttpConfig().getApiBaseUri()
060                                                                        + "/accounts/%s/", apiKey
061                                                        ) + pathGetter.apply(req);
062                                                })
063                                );
064                        }
065                }
066
067                createSubaccount = new Endpoint<>(req -> "subaccounts", HttpMethod.POST);
068                updateSubaccount = new Endpoint<>(req -> "subaccounts/"+req.subaccountApiKey, HttpMethod.PATCH);
069                listSubaccounts = new Endpoint<>(req -> "subaccounts", HttpMethod.GET);
070                getSubaccount = new Endpoint<>(req -> "subaccounts/"+req, HttpMethod.GET);
071                listBalanceTransfers = new Endpoint<>(req -> "balance-transfers", HttpMethod.GET);
072                listCreditTransfers = new Endpoint<>(req -> "credit-transfers", HttpMethod.GET);
073                transferBalance = new Endpoint<>(req -> "balance-transfers", HttpMethod.POST);
074                transferCredit = new Endpoint<>(req -> "credit-transfers", HttpMethod.POST);
075                transferNumber = new Endpoint<>(req -> "transfer-number", HttpMethod.POST);
076        }
077
078        private <T> T requireRequest(T request) {
079                return Objects.requireNonNull(request, "Request is required.");
080        }
081
082        /**
083         * Create a new subaccount under this API primary account.
084         *
085         * @param request Properties for the new subaccount.
086         *
087         * @return Details of the created subaccount.
088         *
089         * @throws SubaccountsResponseException If the request was unsuccessful. This could be for the following reasons:
090         * <ul>
091         *   <li><b>401</b>: Credential is missing or invalid.</li>
092         *       <li><b>403</b>: Action is forbidden.</li>
093         *       <li><b>404</b>: The account ID provided does not exist in our system or you do not have access.</li>
094         *       <li><b>422</b>: Validation error.</li>
095         * </ul>
096         */
097        public Account createSubaccount(CreateSubaccountRequest request) {
098                return createSubaccount.execute(requireRequest(request));
099        }
100
101        /**
102         * Change one or more properties of a subaccount.
103         *
104         * @param request Properties of the subaccount to update.
105         *
106         * @return Details of the updated subaccount.
107         *
108         * @throws SubaccountsResponseException If the request was unsuccessful. This could be for the following reasons:
109         * <ul>
110         *   <li><b>401</b>: Credential is missing or invalid.</li>
111         *       <li><b>403</b>: Action is forbidden.</li>
112         *       <li><b>404</b>: The account ID provided does not exist in our system or you do not have access.</li>
113         *       <li><b>422</b>: Validation error.</li>
114         * </ul>
115         */
116        public Account updateSubaccount(UpdateSubaccountRequest request) {
117                return updateSubaccount.execute(requireRequest(request));
118        }
119
120        /**
121         * Retrieve all subaccounts owned by the primary account.
122         *
123         * @return The primary account details and list of subaccounts associated with it.
124         *
125         * @throws SubaccountsResponseException If the request was unsuccessful. This could be for the following reasons:
126         * <ul>
127         *   <li><b>401</b>: Credential is missing or invalid.</li>
128         *       <li><b>403</b>: Action is forbidden.</li>
129         *       <li><b>404</b>: The account ID provided does not exist in our system or you do not have access.</li>
130         * </ul>
131         */
132        public ListSubaccountsResponse listSubaccounts() {
133                return listSubaccounts.execute(null);
134        }
135
136        /**
137         * Get information about a specific subaccount.
138         *
139         * @param subaccountApiKey Unique ID of the subaccount to retrieve.
140         *
141         * @return Details of the requested subaccount.
142         *
143         * @throws SubaccountsResponseException If the request was unsuccessful. This could be for the following reasons:
144         * <ul>
145         *   <li><b>401</b>: Credential is missing or invalid.</li>
146         *       <li><b>403</b>: Action is forbidden.</li>
147         *       <li><b>404</b>: The account ID provided does not exist in our system or you do not have access.</li>
148         * </ul>
149         */
150        public Account getSubaccount(String subaccountApiKey) {
151                return getSubaccount.execute(AbstractTransfer.validateAccountKey(subaccountApiKey, "Subaccount"));
152        }
153
154        /**
155         * Retrieve a list of credit transfers that have taken place for the primary account within a specified time period.
156         *
157         * @return The list of credit transfers.
158         * @see #listCreditTransfers(ListTransfersFilter)
159         *
160         * @throws SubaccountsResponseException If the request was unsuccessful. This could be for the following reasons:
161         * <ul>
162         *   <li><b>401</b>: Credential is missing or invalid.</li>
163         *       <li><b>403</b>: Action is forbidden.</li>
164         *       <li><b>404</b>: The account ID provided does not exist in our system or you do not have access.</li>
165         * </ul>
166         */
167        public List<MoneyTransfer> listCreditTransfers() {
168                return listCreditTransfers(ListTransfersFilter.builder().build());
169        }
170
171        /**
172         * Retrieve a list of credit transfers that have taken place for the primary account within a specified time period.
173         *
174         * @param filter Additional parameters to narrow down the returned list by.
175         *
176         * @return The list of credit transfers.
177         * @see #listCreditTransfers()
178         *
179         * @throws SubaccountsResponseException If the request was unsuccessful. This could be for the following reasons:
180         * <ul>
181         *   <li><b>401</b>: Credential is missing or invalid.</li>
182         *       <li><b>403</b>: Action is forbidden.</li>
183         *       <li><b>404</b>: The account ID provided does not exist in our system or you do not have access.</li>
184         * </ul>
185         */
186        public List<MoneyTransfer> listCreditTransfers(ListTransfersFilter filter) {
187                return listCreditTransfers.execute(requireRequest(filter)).getCreditTransfers();
188        }
189
190        /**
191         * Retrieve a list of balance transfers that have taken place for the primary account within a specified time period.
192         *
193         * @return The list of balance transfers.
194         * @see #listBalanceTransfers(ListTransfersFilter)
195         *
196         * @throws SubaccountsResponseException If the request was unsuccessful. This could be for the following reasons:
197         * <ul>
198         *   <li><b>401</b>: Credential is missing or invalid.</li>
199         *       <li><b>403</b>: Action is forbidden.</li>
200         *       <li><b>404</b>: The account ID provided does not exist in our system or you do not have access.</li>
201         * </ul>
202         */
203        public List<MoneyTransfer> listBalanceTransfers() {
204                return listBalanceTransfers(ListTransfersFilter.builder().build());
205        }
206
207        /**
208         * Retrieve a list of balance transfers that have taken place for the primary account within a specified time period.
209         *
210         * @param filter Additional parameters to narrow down the returned list by.
211         *
212         * @return The list of balance transfers.
213         * @see #listBalanceTransfers()
214         *
215         * @throws SubaccountsResponseException If the request was unsuccessful. This could be for the following reasons:
216         * <ul>
217         *   <li><b>401</b>: Credential is missing or invalid.</li>
218         *       <li><b>403</b>: Action is forbidden.</li>
219         *       <li><b>404</b>: The account ID provided does not exist in our system or you do not have access.</li>
220         * </ul>
221         */
222        public List<MoneyTransfer> listBalanceTransfers(ListTransfersFilter filter) {
223                return listBalanceTransfers.execute(requireRequest(filter)).getBalanceTransfers();
224        }
225
226        /**
227         * Transfer credit limit between the primary account and one of its subaccounts.
228         *
229         * @param request Properties of the credit transfer.
230         *
231         * @return Details of the transfer if successful.
232         *
233         * @throws SubaccountsResponseException If the request was unsuccessful. This could be for the following reasons:
234         * <ul>
235         *   <li><b>401</b>: Credential is missing or invalid.</li>
236         *       <li><b>403</b>: Action is forbidden.</li>
237         *       <li><b>404</b>: The account ID provided does not exist in our system or you do not have access.</li>
238         *       <li><b>422</b>: Validation error.</li>
239         * </ul>
240         */
241        public MoneyTransfer transferCredit(MoneyTransfer request) {
242                return transferCredit.execute(requireRequest(request));
243        }
244
245        /**
246         * Transfer balance between the primary account and one of its subaccounts.
247         *
248         * @param request Properties of the balance transfer.
249         *
250         * @return Details of the transfer if successful.
251         *
252         * @throws SubaccountsResponseException If the request was unsuccessful. This could be for the following reasons:
253         * <ul>
254         *   <li><b>401</b>: Credential is missing or invalid.</li>
255         *       <li><b>403</b>: Action is forbidden.</li>
256         *       <li><b>404</b>: The account ID provided does not exist in our system or you do not have access.</li>
257         *       <li><b>422</b>: Validation error.</li>
258         * </ul>
259         */
260        public MoneyTransfer transferBalance(MoneyTransfer request) {
261                return transferBalance.execute(requireRequest(request));
262        }
263
264        /**
265         * Transfer a number between subaccounts.
266         *
267         * @param request Properties of the number transfer.
268         *
269         * @return Details of the transfer if successful.
270         *
271         * @throws SubaccountsResponseException If the request was unsuccessful. This could be for the following reasons:
272         * <ul>
273         *   <li><b>401</b>: Credential is missing or invalid.</li>
274         *       <li><b>403</b>: Action is forbidden.</li>
275         *       <li><b>404</b>: The account ID provided does not exist in our system or you do not have access.</li>
276         *       <li><b>409</b>: Transfer conflict.</li>
277         *       <li><b>422</b>: Validation error.</li>
278         * </ul>
279         */
280        public NumberTransfer transferNumber(NumberTransfer request) {
281                return transferNumber.execute(requireRequest(request));
282        }
283}