Class TaxCalculator

java.lang.Object
me.thiagorigonatti.capitalgains.core.TaxCalculator

public class TaxCalculator extends Object

Compute taxes based on a sequence of stock trading operations such as "buy" and "sell". It supports configurable input and output streams, buffer sizes, JSON serialization, and optional filtering of operations.

This class is designed to be flexible and extensible, with a builder-based configuration system that allows customization of behavior such as decimal formatting, predicate-based operation filtering, real-time output flushing, and execution time tracking.

Since:
1.0
  • Constructor Details

    • TaxCalculator

      protected TaxCalculator(TaxCalculator.Builder builder)
      Constructs a new TaxCalculator instance using the provided TaxCalculator.Builder.

      Initializes all necessary components such as input/output streams, object mapper, formatting, predicates, and stock supplier. Also parses any provided arguments using ArgParser.

      Parameters:
      builder - the builder instance containing all configuration and dependencies
  • Method Details

    • getArgs

      public String[] getArgs()
      Returns the command-line arguments.
      Returns:
      the arguments array
    • setArgs

      public void setArgs(String[] args)
      Sets the command-line arguments.
      Parameters:
      args - the arguments array to set
    • getObjectMapper

      public com.fasterxml.jackson.databind.ObjectMapper getObjectMapper()
      Returns the ObjectMapper instance.
      Returns:
      the object mapper
    • setObjectMapper

      public void setObjectMapper(com.fasterxml.jackson.databind.ObjectMapper objectMapper)
      Sets the ObjectMapper instance.
      Parameters:
      objectMapper - the object mapper to set
    • getDecimalFormat

      public DecimalFormat getDecimalFormat()
      Returns the DecimalFormat instance used for formatting numbers.
      Returns:
      the decimal format
    • setDecimalFormat

      public void setDecimalFormat(DecimalFormat decimalFormat)
      Sets the DecimalFormat instance.
      Parameters:
      decimalFormat - the decimal format to set
    • getInputStream

      public InputStream getInputStream()
      Returns the input stream.
      Returns:
      the input stream
    • setInputStream

      public void setInputStream(InputStream inputStream)
      Sets the input stream.
      Parameters:
      inputStream - the input stream to set
    • getBufferSizeIn

      public int getBufferSizeIn()
      Returns the buffer size for input.
      Returns:
      the input buffer size
    • setBufferSizeIn

      public void setBufferSizeIn(int bufferSizeIn)
      Sets the buffer size for input.
      Parameters:
      bufferSizeIn - the input buffer size to set
    • getOutputStream

      public OutputStream getOutputStream()
      Returns the output stream.
      Returns:
      the output stream
    • setOutputStream

      public void setOutputStream(OutputStream outputStream)
      Sets the output stream.
      Parameters:
      outputStream - the output stream to set
    • getBufferSizeOut

      public int getBufferSizeOut()
      Returns the buffer size for output.
      Returns:
      the output buffer size
    • setBufferSizeOut

      public void setBufferSizeOut(int bufferSizeOut)
      Sets the buffer size for output.
      Parameters:
      bufferSizeOut - the output buffer size to set
    • isPrintEveryLine

      public boolean isPrintEveryLine()
      Returns whether each line should be printed.
      Returns:
      true if each line should be printed, false otherwise
    • setPrintEveryLine

      public void setPrintEveryLine(boolean printEveryLine)
      Sets whether each line should be printed.
      Parameters:
      printEveryLine - true to print each line, false otherwise
    • isTimings

      public boolean isTimings()
      Returns whether timing information should be included.
      Returns:
      true if timings are enabled, false otherwise
    • setTimings

      public void setTimings(boolean timings)
      Sets whether timing information should be included.
      Parameters:
      timings - true to enable timings, false to disable
    • getOperationPredicate

      public Predicate<Operation> getOperationPredicate()
      Returns the predicate used to filter operations.
      Returns:
      the operation predicate
    • setOperationPredicate

      public void setOperationPredicate(Predicate<Operation> operationPredicate)
      Sets the predicate used to filter operations.
      Parameters:
      operationPredicate - the operation predicate to set
    • getStockSupplier

      public Supplier<? extends Stock> getStockSupplier()
      Returns the supplier used to create Stock instances.
      Returns:
      the stock supplier
    • setStockSupplier

      public void setStockSupplier(Supplier<? extends Stock> stockSupplier)
      Sets the supplier used to create Stock instances.
      Parameters:
      stockSupplier - the stock supplier to set
    • run

      public void run()
      Processes input data line by line from an InputStream, transforms each line using the calculate(String) method, serializes the result to JSON using objectMapper, and writes it to an OutputStream.

      The method can optionally flush the output after every line and display the total execution time, depending on the values of the printEveryLine and timings flags.

      Additional behavior:

      • If printEveryLine is true, sets the buffer size to 8192 bytes and flushes the output after each line.
      • If timings is true, writes the total execution time in milliseconds at the end of the output.
      Throws:
      RuntimeException - if an IOException occurs while reading from or writing to the streams.
    • calculate

      protected com.fasterxml.jackson.databind.node.ArrayNode calculate(String line) throws com.fasterxml.jackson.core.JsonProcessingException
      Parses a JSON-formatted string representing a list of operations, processes each operation to calculate a tax, and returns the result as an ArrayNode. The tax calculation now considers the ticker field for each operation, ensuring that tax is calculated separately for different stocks.

      Each operation is processed using the processOperation method, and the resulting tax is formatted using decimalFormat and added to the returned JSON array as an object with a "tax" field.

      Filtering:

      • If operationPredicate is set, it is used to filter the operations.
      • If not set, all operations are processed.

      Ticker Logic:

      • The tax calculation now groups operations by their ticker value, meaning that each stock's tax is calculated independently, considering the operations for that specific stock.
      • The operations for the same ticker are accumulated and processed together.
      Parameters:
      line - the input JSON string representing a list of operations
      Returns:
      an ArrayNode containing one object per operation, each with a formatted "tax" field
      Throws:
      com.fasterxml.jackson.core.JsonProcessingException - if the input string cannot be parsed into a list of Operation objects
    • processOperation

      protected BigDecimal processOperation(Operation op, Stock stock)
      Processes a single operation on the given Stock instance, modifying its state accordingly and returning the calculated tax amount (if applicable).

      Supports the following operations:

      • "buy" — Updates the stock with the purchased quantity and unit cost. Returns zero tax.
      • "sell" — Updates the stock based on the sale and returns the calculated tax as a BigDecimal.
      Parameters:
      op - the Operation to be processed
      stock - the Stock instance to apply the operation to
      Returns:
      the calculated tax for the operation, or BigDecimal.ZERO for a "buy"
      Throws:
      InvalidOperationException - if the operation type is not recognized