package pt.rupeal.invoicexpress.server; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; import java.text.MessageFormat; import java.util.Collection; import java.util.SortedMap; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.methods.HttpPut; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.protocol.BasicHttpContext; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import pt.rupeal.invoicexpress.MainActivity; import pt.rupeal.invoicexpress.R; import pt.rupeal.invoicexpress.enums.DocumentStatusEnum; import pt.rupeal.invoicexpress.enums.DocumentTypeEnum; import pt.rupeal.invoicexpress.model.ContactModel; import pt.rupeal.invoicexpress.model.DocumentModel; import pt.rupeal.invoicexpress.model.DocumentsModel; import pt.rupeal.invoicexpress.utils.InvoiceXpressError.InvoiceXpressErrorType; import pt.rupeal.invoicexpress.utils.InvoiceXpressException; import android.content.Context; import android.os.Bundle; import android.util.Log; public class DocumentChangeStatusRestHandler extends AsyncTask<String, Void, String> { private DocumentModel document; private StringBuffer responseXml; public DocumentChangeStatusRestHandler(Context context, DocumentModel document) { this.context = context; this.document = document; } @Override protected String doInBackground(String... params) { HttpPut httpPut = new HttpPut(buildRequestHttpPost()); try { StringEntity entity = new StringEntity(buildXmlRequest(params), "UTF-8"); entity.setContentType("application/xml; charset=utf-8"); httpPut.setEntity(entity); DefaultHttpClient httpClient = new DefaultHttpClient(InvoiceXpress.getHttpParameters()); HttpResponse response = httpClient.execute(httpPut, new BasicHttpContext()); BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF-8")); responseXml = new StringBuffer(); String line; while ((line = reader.readLine()) != null) { responseXml.append(line); } if(response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { if(InvoiceXpress.DEBUG) { Log.d(this.getClass().getCanonicalName(), "Status Code: " + response.getStatusLine().getStatusCode()); Log.d(this.getClass().getCanonicalName(), responseXml.toString()); } return ""; } if(InvoiceXpress.DEBUG) { Log.d(this.getClass().getCanonicalName(), responseXml.toString()); } return parseNewStatus(); } catch (UnsupportedEncodingException e) { Log.e(this.getClass().getCanonicalName(), e.getMessage(), e); setError(R.string.error_change_status_unexpected, InvoiceXpressErrorType.ERROR); } catch (ClientProtocolException e) { Log.e(this.getClass().getCanonicalName(), e.getMessage(), e); setError(R.string.error_change_status_unexpected, InvoiceXpressErrorType.ERROR); } catch (IOException e) { Log.e(this.getClass().getCanonicalName(), e.getMessage(), e); setError(R.string.error_change_status_unexpected, InvoiceXpressErrorType.ERROR); } catch (InvoiceXpressException e) { Log.e(this.getClass().getCanonicalName(), e.getMessage(), e); setError(e.getMessage(), InvoiceXpressErrorType.ERROR); } return ""; } private String buildRequestHttpPost() { StringBuffer request = new StringBuffer(InvoiceXpress.getInstance().getActiveAccount().getUrl()); request.append(DocumentTypeEnum.getUrlOperations(document.getType())); request.append("/").append(document.getId()); request.append("/").append("change-state.xml"); request.append("?api_key=" + InvoiceXpress.getInstance().getActiveAccount().getApiKey()); if(InvoiceXpress.DEBUG) { Log.d(DocumentChangeStatusRestHandler.class.getCanonicalName(), request.toString()); } return request.toString(); } private MessageFormat xmlRequest = new MessageFormat ( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<invoice>" + "<state>{0}</state>" + "<message>{1}</message>" + "</invoice>"); private String buildXmlRequest(String... params) { Object[] args = {params[0], params[1]}; String xmlRequestFormated = xmlRequest.format(args); if(InvoiceXpress.DEBUG) { Log.d(this.getClass().getCanonicalName(), xmlRequestFormated); } return xmlRequestFormated; } private String parseNewStatus() throws InvoiceXpressException { InvoiceXpressParser parser = new InvoiceXpressParser(context); Document documentDomElement = parser.getDomElement(responseXml.toString()); NodeList nodeList = documentDomElement.getElementsByTagName(DocumentTypeEnum.getTagXmlMainChildsByDocType(document.getType())); return parser.getValue((Element) nodeList.item(0), "state"); } @Override protected void onPostExecute(String result) { super.onPostExecute(result); // if the result is empty then an error will be showed if(result.isEmpty()) { processReturnedError(); } // check if there is an error if(existsError()) { processError(); return; } // if the document was deleted then the application will delete it and will show the documents list if(DocumentStatusEnum.isDeleted(result)) { // remove cached document // find where is the document and delete it from application deleteDocument(); // hide document details and show documents list String lastFragmentTag = InvoiceXpress.getInstance().getLastFragment().getFragmentTag(); ((MainActivity) context).removeFragment(lastFragmentTag); } else { // set new status document.setStatus(result); // refresh fragment Bundle args = new Bundle(); args.putSerializable(DocumentModel.DOCUMENT, document); ((MainActivity) context).refreshFragment(args); } } /** * Delete document from cache application. * @return if a document was deleted then return true else return false */ private boolean deleteDocument() { boolean result = false; // try to find document in documents map // SortedMap<Integer, DocumentsModel> documentsSortedMap = InvoiceXpress.getInstance().getDocuments().getDocuments(); // delete document from all documents list SortedMap<Integer, DocumentsModel> documentsAllSortedMap = InvoiceXpress.getInstance().getDocuments(DocumentTypeEnum.ALL.getValue()).getDocuments(); if(!documentsAllSortedMap.isEmpty()) { Collection<DocumentsModel> filterKeys = documentsAllSortedMap.values(); for (DocumentsModel documentsModel : filterKeys) { DocumentModel documentDeleted = documentsModel.getDocuments().remove(document.getId()); // log if(InvoiceXpress.DEBUG) { if(documentDeleted != null) { Log.d(this.getClass().getCanonicalName(), "Document with sequenceNumber: " + documentDeleted.getSequenceNumber() + " was deleted from documents cache."); break; } } } } // delete document document from respective documents type list SortedMap<Integer, DocumentsModel> documentsTypeSortedMap = InvoiceXpress.getInstance().getDocuments(document.getType()).getDocuments(); if(!documentsTypeSortedMap.isEmpty()) { Collection<DocumentsModel> filterKeys = documentsTypeSortedMap.values(); for (DocumentsModel documentsModel : filterKeys) { DocumentModel documentDeleted = documentsModel.getDocuments().remove(document.getId()); // log if(InvoiceXpress.DEBUG) { if(documentDeleted != null) { Log.d(this.getClass().getCanonicalName(), "Document with sequenceNumber: " + documentDeleted.getSequenceNumber() + " was deleted from documents cache."); break; } } } } // try to find document in contacts documents map Collection<ContactModel> contacts = InvoiceXpress.getInstance().getContacts().values(); for (ContactModel contact : contacts) { Collection<DocumentsModel> filterKeys = contact.getDocuments().getDocuments().values(); for (DocumentsModel documentsModel : filterKeys) { DocumentModel documentDeleted = documentsModel.getDocuments().remove(document.getId()); // log if(InvoiceXpress.DEBUG) { if(documentDeleted != null) { result = result || true; Log.d(this.getClass().getCanonicalName(), "Document with sequenceNumber: " + documentDeleted.getSequenceNumber() + " was deleted from documents cache."); break; } } } } return result; } private static final String ERROR_DATE = "Date can not be before last sent invoice of this sequence "; private static final String ERROR_CANCEL_MESSAGE_EMPTY = "Cancel message can't be blank"; private static final String ERROR_ALREADY_SENT_TO_AT = "Cannot cancel, document already sent to AT"; private void processReturnedError() { try { InvoiceXpressParser parser = new InvoiceXpressParser(context); Document documentDomElement = parser.getDomElement(responseXml.toString()); NodeList errorsList = documentDomElement.getElementsByTagName("errors"); Node error = errorsList.item(0); String errorDescr = parser.getValue((Element) error, "error"); if(errorDescr.contains(ERROR_DATE)) { String msg = context.getResources().getString(R.string.error_change_status_date) + " " + errorDescr.substring(ERROR_DATE.length(), errorDescr.length()); setError(msg, InvoiceXpressErrorType.ERROR); } else if(errorDescr.equals(ERROR_CANCEL_MESSAGE_EMPTY)) { setError(R.string.error_change_status_cancel_empty_message, InvoiceXpressErrorType.ERROR); } else if(errorDescr.equals(ERROR_ALREADY_SENT_TO_AT)) { setError(R.string.error_change_status_already_sent_to_at, InvoiceXpressErrorType.ERROR); } } catch (InvoiceXpressException e) { Log.e(this.getClass().getCanonicalName(), e.getMessage(), e); setError(e.getMessage(), InvoiceXpressErrorType.ERROR); } } }